Limited time for Lifetime Access to 12,400+ Components, UI Builder and AI Assistant! 👇
🚀 Get it Now!

Tailwind Dynamic Classes Explained

Learn how to use dynamic class names in Tailwind CSS

by Yucel Faruk Sahan
9 min read
Updated on

Tailwind Dynamic Classes Explained: lookup table

When working with modern CSS frameworks, you might have run into a head-scratcher: dynamic class names. If you’ve ever tried to generate your class names on the fly with Tailwind CSS, you know that things don’t always go as expected.

In this article, we’re breaking down why dynamically generated class names in Tailwind can be problematic, what happens behind the scenes, and how you can work around these issues while keeping your code clean and maintainable.

How Tailwind Works Under the Hood

Tailwind CSS relies on a process called static analysis. During the build process, Tailwind scans your source files for class names and then generates a CSS file that includes only the classes it finds. This technique, often called “tree-shaking” or “purging,” keeps your CSS bundle lean and fast.

For example, if your project only uses bg-blue-500 and p-3, Tailwind will only generate those classes. If you try to use a class like bg-${color}-500, Tailwind sees it as a variable expression rather than a literal string. Since it doesn’t match any specific class, the CSS for it is never generated. That’s why, despite your best efforts, your dynamic styling sometimes ends up not working at all.Common Pitfalls When Using Dynamic Classes

Let’s go over a few common scenarios where dynamic class generation trips you up:

  1. String Interpolation:
    When you use string interpolation (e.g., bg-${color}-500), Tailwind cannot parse the complete class name from your source code.

  2. Conditional Ternary Operators:
    Even if you write something like { isActive ? 'bg-green-500' : 'bg-red-500' }, Tailwind will see the two complete class names—but only if they’re clearly separated in your code. If they’re part of a more complex concatenation, you might run into issues.

  3. Array Joining:
    Combining classes in an array and then joining them (e.g., ['bg-blue-500', isActive && 'text-white'].join(' ')) can also confuse the static analyzer if not done carefully.

  4. Using Variables for Class Names:
    If you store class names in variables or import them from another module, Tailwind might not pick them up unless they are explicitly referenced in the files it scans.

Understanding these pitfalls is crucial. They highlight why relying on fully static class names is the safest route when working with Tailwind.


Practical Workarounds and Techniques

Now that we’ve seen the problem, let’s explore some practical solutions. Here are several techniques you can use to work around the limitations of dynamic class names in Tailwind CSS.

Lookup Tables for Class Names

One of the simplest and most effective techniques is using a lookup table. Instead of dynamically generating class names on the fly, define an object where the keys represent the possible values and the values are the complete class names.

For example:

const bgColorLookup = {
  blue: 'bg-blue-500',
  red: 'bg-red-500',
  green: 'bg-green-500',
  yellow: 'bg-yellow-500',
};

function MyButton({ color }) {
  return (
    <button className={`${bgColorLookup[color]} p-3 rounded`}>
      Click me
    </button>
  );
}

This approach ensures that Tailwind can see all the possible classes during its scan, so nothing gets left out. It also makes your code more predictable and easier to maintain.

Safelisting Classes in Configuration

Another method is to explicitly safelist your dynamic class names in your Tailwind configuration file. The safelist feature allows you to specify a list or pattern of classes that should always be included, even if they don’t appear directly in your source code.

Here’s an example of how you might add a safelist:

// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  safelist: [
    {
      pattern: /bg-(blue|red|green|yellow)-500/,
    },
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

With this configuration, Tailwind will always generate the classes that match the pattern, ensuring your dynamically generated classes are available at runtime.

Using Inline Styles or CSS Variables

Sometimes you need a bit more flexibility than what lookup tables or safelisting can provide. In such cases, consider using inline styles or CSS variables. This is especially useful when you need to apply values that might not fit within Tailwind’s utility class structure.

For example, if you need a dynamic padding value, you could do:

function DynamicPadding({ paddingValue }) {
  return (
    <div style={{ padding: paddingValue }}>
      This div has dynamic padding!
    </div>
  );
}

For pseudo-elements or more complex scenarios, CSS variables can be a lifesaver. Instead of trying to generate a dynamic class, set a CSS variable on an element and reference it in your Tailwind class:

<div
  className="after:p-[var(--custom-padding)]"
  style={{ '--custom-padding': '20px' }}
>
  Content with custom pseudo-element padding.
</div>

This method lets you retain the benefits of Tailwind’s utility classes while still injecting dynamic values where needed.

Combining Tailwind with CSS-in-JS

If your project demands a lot of dynamic styling, you might consider using a CSS-in-JS library alongside Tailwind. Libraries like Emotion or Styled Components let you define styles dynamically and then combine them with Tailwind’s utility classes.

For example, using Emotion:

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

const dynamicStyle = (color) => css`
  background-color: ${color};
  padding: 1rem;
  border-radius: 0.5rem;
`;

function StyledButton({ color, children }) {
  return (
    <button css={dynamicStyle(color)} className="text-white font-bold">
      {children}
    </button>
  );
}

This setup gives you the best of both worlds—the efficiency of Tailwind for most of your styling and the flexibility of CSS-in-JS for dynamic parts.


Real-World Examples

Let’s look at a few scenarios where these techniques come into play in a real project.

Example 1: Dynamic Theme Switching

Imagine you’re building a dashboard that supports multiple themes. Users can select a theme (for instance, “light” or “dark”), and various components need to update their styles accordingly. Using a lookup table makes this easy:

const themeStyles = {
  light: {
    bg: 'bg-white',
    text: 'text-gray-900',
  },
  dark: {
    bg: 'bg-gray-900',
    text: 'text-white',
  },
};

function DashboardCard({ theme, title, content }) {
  return (
    <div className={`${themeStyles[theme].bg} p-4 rounded shadow`}>
      <h2 className={`text-xl ${themeStyles[theme].text}`}>{title}</h2>
      <p className={themeStyles[theme].text}>{content}</p>
    </div>
  );
}

Tailwind sees the complete class names in your lookup object, so everything works seamlessly.

Example 2: User-Generated Data

If your application lets users choose custom colors from a palette, you might worry about generating classes like bg-${userColor}-500. Instead of constructing these classes on the fly, you could create a predefined set of colors that you support and then use a lookup table. This both protects your code against missing classes and limits the scope to a manageable set of options.

const supportedColors = {
  violet: 'bg-violet-500',
  indigo: 'bg-indigo-500',
  teal: 'bg-teal-500',
  amber: 'bg-amber-500',
};

function UserCard({ userColor, name }) {
  // Fallback to a default color if the user selection is unsupported
  const bgClass = supportedColors[userColor] || 'bg-gray-500';

  return (
    <div className={`${bgClass} p-6 rounded-lg`}>
      <h3 className="text-white text-lg">{name}</h3>
    </div>
  );
}

Here, the lookup table ensures that Tailwind generates the necessary styles for each supported option.

Example 3: Responsive Design with Dynamic Adjustments

Suppose you need to adjust spacing or font sizes dynamically based on screen size or user preferences. While Tailwind’s responsive utilities cover many cases, sometimes you need an extra bit of dynamism. By combining inline styles or CSS variables with Tailwind classes, you can achieve this elegantly.

function ResponsiveCard({ paddingValue, fontSizeValue }) {
  return (
    <div
      className="border rounded-lg shadow-lg"
      style={{
        padding: paddingValue,
        fontSize: fontSizeValue,
      }}
    >
      <p>This card adjusts its padding and font size dynamically.</p>
    </div>
  );
}

For more complex responsive behaviors, consider using CSS variables that update based on media queries. This way, you keep your Tailwind classes intact while letting dynamic values change as needed.

Best Practices and Tips

Over time, I’ve picked up a few best practices that can help you avoid common pitfalls when working with dynamic styling in Tailwind CSS. Here are some tips to keep in mind:

  1. Plan Your Design System:
    Define the range of styles you expect to use before writing code. A well-thought-out design system with predefined values minimizes the need for truly dynamic class names.

  2. Use Lookup Tables:
    Lookup tables are a powerful way to handle conditional styling. They keep your code organized and make it easy to update styles in one centralized location.

  3. Explicit Safelisting:
    If you know you’ll need to generate classes dynamically, use Tailwind’s safelist option in your configuration. This guarantees that your necessary styles won’t be purged.

  4. Keep It Simple:
    When in doubt, stick to static class names. Sometimes it’s better to lean on the flexibility of inline styles or CSS variables for one-off dynamic values rather than trying to over-engineer a solution.

  5. Leverage Community Tools:
    There are several libraries—like classnames and tailwind-merge—that help manage conditional classes. They can simplify your code and reduce the risk of errors.

  6. Test Thoroughly:
    Because Tailwind’s build process relies on static analysis, make sure to test your components in different scenarios. This helps catch any cases where a dynamic class might not be generated as expected.

  7. Keep Learning:
    Tailwind’s documentation on content scanning and dynamic class names is very detailed. Spend some time reviewing it, and keep an eye on community blogs and forums for new insights and techniques.

Wrapping Up

Working with dynamic class names in Tailwind CSS can be tricky, but it doesn’t have to be a roadblock. By understanding how Tailwind works under the hood and using strategies like lookup tables, safelisting, inline styles, and CSS-in-JS solutions, you can build robust, maintainable applications without sacrificing flexibility.

Remember, the key is ensuring that Tailwind sees the full class names during its build process. Once you design your code to follow that rule, you’re well on your way to creating a styling system that’s both powerful and predictable.

I hope this post helps you navigate the challenges and discover practical techniques for dynamic styling. Whether you’re building a complex dashboard or a simple interface, the strategies discussed here can be adapted to suit your needs. Experiment with these approaches, adjust your configuration as needed, and most importantly—enjoy the process of crafting clean and efficient code.

FAQ

Why do my dynamic Tailwind classes sometimes not work?

Because Tailwind only scans for complete, static class names during build time, so dynamically constructed names may not be detected.

How can I ensure my dynamic styles are applied?

Use strategies like lookup tables, safelisting in your configuration, or inline styles/CSS variables to make sure Tailwind includes the required classes.

What is a lookup table in this context?

It’s a predefined object that maps dynamic values to full Tailwind class names, ensuring all classes are visible during build time.

Q4: Can I mix Tailwind with other styling approaches for dynamic classes?

Yes, combining Tailwind with CSS-in-JS libraries or inline styles gives you the flexibility to handle dynamic styling without breaking Tailwind’s static analysis.

Yucel Faruk Sahan

Yucel is a digital product maker and content writer specializing in full-stack development. He is passionate about crafting engaging content and creating innovative solutions that bridge technology and user needs. In his free time, he enjoys discovering new technologies and drawing inspiration from the great outdoors.