Skip to Content

2024.03.06

Dynamic CSS In Components

Styling components via props and dynamic css.

I was talking with a design systems team last week about some of the problems they’ve been working through, and one of the engineers described a problem I’ve seen before. They wanted to write a component that accepted a prop which controls some aspect of that components style. They attempted to do it like this:

// In use
<MyButton color="blue"> Neat Button </MyButton

// In Component
<button class="button-{props.color}">
  …
</button>

// With styles:
.button-blue {}
.button-green {}
.button-red {}

The problem with this approach is that a number of frameworks will include a css optimization step where any css selectors that don’t make an appearance in the DOM get dropped. Setting the class name from an API response means the css compiler wont pick them up. Sometimes the compiler will also rename these classes to generated ids to ensure there are no namespace collisions.

One solution is to force the compiler to keep all these classes around on the global scope, so they get applied when they show up. Naturally, this removes a lot of the benefit of optimized, component level css.

Custom Properties to the Rescue

Luckiy we have more tools available to us than just class names! Let’s reduce our css to a single classname that uses a custom property to define the variables.

.button {
  color: var(--button-color);
}

Our component can surface the same interface:

<MyButton color="blue">…</MyButton>

And we we adjust where that prop gets rendered in the template:

<button
  style="--color: {pops.color};"
  class="button">
  …
</button>

Or, if we want to get fancier with design token colors rather than passing raw values;

<button
  style="--color: var(--{pops.color});"
  class="button">
  …
</button>

If we have design token properties set at the root, we can map blue to a precise value like #0f0ade or #524eb7.

This works for lots of different properties! I think the only place I’ve wanted to use this approach but not been able to is Media Queries.

Use in Data-driven UI

One place where I particularly like using this approach is in rendering grid layouts with a variable number of columns – lets say our data can dynamically change between 3 to 6 columns, we can use this this approach to style display: grid container to match the data.

A component like:

<MyGrid data={arrayOfObjects} />

Can then render it’s DOM like:

<div 
	class="grid-table"
	style="--cols: {Object.keys(arrayOfObjects).length}">
…
</>

With css like:

.grid-table {
	display: grid;
	grid-template-columns: repeat(var(--cols), 1fr);
}

Neat!

Elsewhere

css

© 2026