Skip to content

Dynamic Classes in Tailwind CSS

CSS/

If you have tried passing a dynamic value to a Tailwind CSS class, it will most likely fail to work. Although the class name is properly applied to the HTML element, the corresponding styles are not.

Tailwind CSS determines what styles to bundle by parsing the files you specify in content property inside tailwindcss.config.cjs file.

module.exports = {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
};

Since Tailwind has a massive collection of classes, it doesn’t include them all in the final stylesheet. To reduce the size of the bundle, it only compiles the styles for classes that you mention inside your code.

When Tailwind parses your source files and sees a class that contains a dynamic value, it doesn’t recognize it. Therefore those styles are not compiled.

// ❌ using a dynamic value within Tailwind CSS class
<p className={`text-${size}xl`}>Hello</p>

// ❌ using a variable that contains a dynamic value
const style = `text-${size}xl`;
<p className={style}>Hello</p>

If you mention the exact class name anywhere in your code, its styles will be compiled.

let style;

if (size === 2) {
  // ✅ referencing a Tailwind CSS class
  style = `text-2xl`;
}

<p className={style}>Hello</p>

Even mentioning the class in a comment works.

// ✅
const size = 2; // size can be text-2xl or text-4xl
<p className={`text-${size}xl`}>Hello</p>

Or, if you have used the full class name anywhere else in your code, it will work.

// ✅
<p className={`text-4xl`}>Hello</p>

const size = 4;
<p className={`text-${size}xl`}>World</p>

Of course these are not real solutions. A comment can be deleted or the other element using that class name can be modified to use a different class.

The solution is to use full Tailwind CSS class names in your code. Do not use partial names along with dynamic values. Use the dynamic value to generate the full class name in your code.

Setting Class Name Dynamically

To set a Tailwind CSS class name dynamically, I will use a Heading component as an example.

It’s a React component that accepts a level prop and returns h1-h6 HTML heading element depending on level value.

To apply a different text size, you might be tempted to use a dynamic class name like so:

export default function Heading({ level, size, children }) {
  const Heading = `h${level}`;

  return (
    <Heading className={`${size ? 'text-${size}xl' : 'text-base'}`}>
      {children}
    </Heading>
  );
}

But, as determined previously, it won’t work, because Tailwind doesn’t recognize text-${size}xl as an actual class name from its collection.

You need to mention classes that Tailwind recognizes in your code.

export default function Heading({ level, size, children }) {
  const Heading = `h${level}`;
  let style;

  switch(size) {
    case 4:
      style = 'text-4xl';
      break;
    case 2:
      style = 'text-2xl';
      break;
    // ...other cases
  }

  return (
    <Heading className={style}>
      {children}
    </Heading>
  );
}

Safelisting Classes

Alternatively, you use safelisting to list all the classes whose styles you want to be compiled, even if these classes are not mentioned in your code.

Adjust your tailwind.config.cjs file and configure the safelist.

module.exports = {
  safelist: [
    'text-4xl',
    'text-2xl',
    'text-xl',
    'text-base',
  ],
};

You can also use patterns for repetitive styles.

module.exports = {
  safelist: [
    {
      pattern: /text-(base|xl|2xl|4xl)/,
    },
  ],
};