I want to share something exciting solution with you. The solution is about solving the dynamic class value that tailwindcss normally does not work with.
If you're new to tailwindcss, You can learn here how to integrate tailwindcss in your project
I’m inspired by this article written by Ryan Partridge, Special Thanks to him 🙏
In the above article, Ryan provides the solution with tailwindcss class names, but in this article, I’m extending this solution and solving the problem with dynamic values using tailwind arbitrary values.
Arbitrary values are introduced in tailwindcss in v2.1. This new powerful feature becomes possible due to the JIT compiler.
What is the actual problem?
While I’m working on a react project, for styling i'm using Tailwindcss & ShadCN design library.
While building dashboard stats cards, I see each card has a different color. The card also includes an icon with its background color in a darker shade.
So the quick solution I found out is to add a color hexadecimal value in the tailwindcss bg-[#D45113]
class. But, here is the problem… Tailwind does not allow dynamically added values, because as we know the JIT compiler runs on demand and only accepts statically defined values.
This is where I'm completely stuck, because provided color values does not actually converted to CSS properties and hence, nothing is painted in a browser.
Let me explain this with an example code. Imagine your data looks something like this:
const statsData = [
{
stats: 4585,
color: "#48CF7357",
iconBg: "#49D074",
icon: "icon here..."
}, {
stats: 95,
color: "#F5A45957",
iconBg: "#FDAF67",
icon: "icon here..."
}, {
stats: 1022,
color: "#B486EE57",
iconBg: "#B688EF",
icon: "icon here..."
}, {
stats: 105,
color: "#413F5A57",
iconBg: "#4E4B65",
icon: "icon here..."
}, {
stats: 105,
color: "#4E4B65",
iconBg: "#7569FC",
icon: "icon here..."
}, {
stats: 105,
color: "#F6323A57",
iconBg: "#FE474F",
icon: "icon here..."
}
];
Each object in the array has a different color
and iconBg
colors in hexadecimal format.
Now, take a look at our Card Component which takes these color values while looping through this data.
export default function DashCard({
icon,
iconClass,
cardClass
}) {
return (
<Card className={`${cardClass}`}>
<CardContent>
<div
className={`${iconClass}`}
>{icon}div>
CardContent>
Card>
)
}
Our card component is simple, it takes classes as props from parents and applies style using tailwindcss classes.
Now, take a look at our parent component:
function DashboardCardWrapper() {
return (
<section className="grid grid-cols-3 gap-4">
{
statsData && statsData?.map((item, idx) =>
<DashCard
key={idx}
icon={item.icon}
iconClass={`text-white bg-[${item.iconBg}]}
cardClass={`bg-[`${item.color}] border-[`${item.color}`]}
/>
)
}
)
}
In our parent component, stateData
is used with map()
array method for applying a loop to our DashCard
component.
You may have noticed that I'm assigning dynamic color values bg-[${item.iconBg}]
using arbitrary values style.
But, Unfortunately… colors do not apply to our card component.
How to apply dynamic values in arbitrary values in tailwindcss?
To understand this solution, we need to understand how JIT (Just-In-Time) compiler generates tailwindcss classes?
The tailwind's JIT compiler looks for the static class names in the code to generate the related CSS for us.
See the below example code:
<div className={`mt-[${size === 'lg' ? '22px' : '17px' }]`}>div>
The above example does not work again, because, the Just-in-Time (JIT) compiler is designed to generate utility-based CSS styles on demand, at the time of development, or at build time.
Like, In the above example, the javascript express cannot be compiled, because it is unknown and processed at the runtime.
Take a look at this example, which works well for us:
<div className={ size === 'lg' ? 'mt-[22px]' : 'mt-[17px]' }>div>
This works because the class name is known to the JIT compiler and the class name is served statically.
So, in our case, to make it work and apply these hexadecimal color values. It is required that tailwindcss must know these values on demand so that they are served statically.
So, the solution I have found in the above-mentioned article is to use the safelist
option of tailwind.config.js
file.
What is safelist
in Tailwind CSS?
Tailwind CSS uses a Just-in-Time (JIT) compiler that generates only the CSS classes you use in your HTML, JS, or template files. This makes your final CSS bundle much smaller and faster.
However, sometimes you use class names dynamically—like bg-${color}
or text-${variant}
—and the compiler can’t see those in your code. So it won’t include them in the final CSS. That's where the safelist
option comes in!
The Safelist option tells the tailwindcss to always include these classes in the final CSS bundle, even if you don't see them in a source code.
In our case, keeping things simple, I've defines an array of colors and generate static classes for background, border and text using and assigns these classes to safelist
option.
const colours = ["#48CF7357", "#49D074", "#F5A45957"];
const safeColours = colours.flatMap((color) => [ `bg-[${color}]`, `border-[${color}]`, `text-[${color}]`]);
module.exports = {
content: ["./src/**/*.{html,js}"],
safelist: [...safeColours], // provide generated classes here
theme: {
extend: {},
},
plugins: [],
}
Now, if you run the code again, you’ll see colors applied on cards and our code works perfectly as we want.
What are the drawbacks of using safelist soo much?
As we see, this option is very handy, but it is important to know the drawbacks as well to keep things simple and in control.
1) Increase the bundle size
As I said before, JIT compiler generate static used properties in a final CSS bundle, which makes the bundle size very small, and good for optimization purpose.
The Safelist option always includes your static classes, whether they are used in a project or not, saving soo much classes in a safelist might increase the final CSS bundle size of your project.
2) Manually Managing
You have to manually keep track of what to safelist. If you forget to add a class, it won't show up, even if your code is trying to use it dynamically. This might leads of unknown bugs in our code.
3) Harder to Scale
As the app grows the safelist might grows too, and it becomes a maintenance burden.
Wrapping Up
The safelist
feature in Tailwind CSS is useful for including classes that are generated dynamically and might not be detected during build time. It’s great for scenarios like theme switching or styling from CMS content, but if overused, it can increase your CSS bundle size and affect performance. Since it requires manual setup, it also adds some maintenance overhead. Used wisely, safelist helps balance flexibility with performance in dynamic Tailwind projects.
This Blog Originally Posted at Programmingly.dev. Understand & Learn Web by Joining our Newsletter for Web development & Design Articles