Efficiently Manage Dynamic Tailwind CSS with Safelist & Theming


Introduction
Tailwind CSS is a utility-first CSS framework that’s loved for its speed, scalability, and productivity. But when building enterprise-level apps that integrate with a CMS like Sitecore and support multiple brands or single brand, developers often run into a major limitation: dynamic class names don’t work as expected. Solving this issue can significantly enhance the efficiency and maintainability of multi-brand environments.
This blog is a detailed guide that walks you through:
What Tailwind CSS is and how its Just-In-Time (JIT) engine works
Why dynamic classes fail in Tailwind
How the
safelist
feature helpsHow we integrated this into a single or multi-sites project
Table of contents
What is Tailwind CSS?
How Tailwind's JIT Engine Works
What Are Dynamic Classes?
What is the
safelist
in Tailwind?Real-World Problem: Dynamic Styles in Multi-Brand Apps
Simple Real-World Example (Multi-Brand Card)
Summary
1. What is Tailwind CSS?
Tailwind CSS is a utility-first CSS framework that allows you to build designs directly in your markup using small, composable utility classes.
Example:
<div class="bg-blue-500 text-white p-4 rounded">Submit</div>
Instead of writing custom stylesheets, Tailwind encourages using these pre-defined utility classes. It compiles only the classes found in your source code, keeping your final CSS bundle small and fast.
2. How Tailwind's JIT Engine Works
Tailwind uses a Just-In-Time (JIT) engine that scans your project files at build time and compiles only the CSS classes that it can statically detect.
✅ This works:
<div class="text-sm bg-red-500 h-12">Static class example</div>
❌ This fails:
const color = 'red';
return <div className={`bg-${color}-500`}>Dynamic class example</div>;
Because Tailwind doesn’t evaluate JavaScript logic, it never sees bg-red-500
during its scan—so it never generates that CSS.
3. What Are Dynamic Classes?
Dynamic classes are class names built using variables or expressions at runtime.
Example:
const height = '40px';
return <div className={`h-[${height}]`}>Dynamic class example</div>;
Even though height
becomes 40px
, Tailwind doesn't know that ahead of time. It needs exact strings like h-[40px]
in your code to include them in the final CSS.
⚠️ This problem affects both development and production.
4. What is the safelist
in Tailwind?
To handle this limitation, Tailwind introduced a config option called safelist
.
📌 Definition:
The
safelist
array in yourtailwind.config.js
allows you to specify classes that should always be included in your compiled CSS—even if Tailwind doesn't detect them in your code.
Example:
// tailwind.config.js
module.exports = {
safelist: [
'bg-red-500',
'h-[40px]',
'skew-x-[10deg]',
],
};
5. Real-World Problem: Dynamic Styles in Multi-Brand Apps
Our project is an enterprise-grade web app powered by Sitecore CMS. It supports multiple brands such as:
Site-A
Site-B
Site-C
Site-D
Each brand provides its own tokens for spacing, colors, shadows, etc., via JSON. These token values are not known until runtime and are injected into components dynamically.
Token file.
{
"Site-A": { "bg": "#fefefe", "height": "100px" },
"Site-B": { "bg": "#efefef", "height": "120px" },
"Site-C": { "bg": "#dedede", "height": "90px" },
"Site-D": { "bg": "#f2f2f2", "height": "70px" }
}
You try to render a component like this:
<div className={`bg-[${tokens.bg}] h-[${tokens.height}]`}>Card</div>
❌ Tailwind JIT ignores these because it can’t resolve their values statically.
6. Simple Real-World Example (Multi-Brand Card)
Let’s understand this with a simple example: You’re creating a Card
component that changes background color and height based on a brand.
❌ Problematic Code
const brand = 'Site-A';
const styles = {
Site-A: { bg: '#fefefe', height: '100px' },
Site-B: { bg: '#efefef', height: '120px' },
Site-C: { bg: '#dedede', height: '90px' },
Site-D: { bg: '#f2f2f2', height: '70px' }
};
return (
<div className={`bg-[${styles[brand].bg}] h-[${styles[brand].height}]`}>
Branded Card
</div>
);
This will fail because Tailwind can't detect dynamic strings.
✅ Solution with Safelist
Let’s fix this using safelist
and a structured approach.
Step 1: Define brand styles
const brandStyles = {
Site-A: { bg: '#fefefe', height: '100px' },
Site-B: { bg: '#efefef', height: '120px' },
Site-C: { bg: '#dedede', height: '90px' },
Site-D: { bg: '#f2f2f2', height: '70px' }
};
Step 2: Generate the Safelist Programmatically
const safelist = Object?.values(brandStyles)?.flatMap(({ bg, height }) => [
`bg-[${bg}]`,
`h-[${height}]`
]);
This gives you:
[
'bg-[#fefefe]', 'h-[100px]',
'bg-[#efefef]', 'h-[120px]',
'bg-[#dedede]', 'h-[90px]',
'bg-[#f2f2f2]', 'h-[70px]'
]
Step 3: Add to tailwind.config.js
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
safelist: safelist,
};
Step 4: Use in component
const brand = 'Site-A';
const styles = brandStyles[brand];
return (
<div className={`bg-[${styles.bg}] h-[${styles.height}]`}>
Branded Card
</div>
);
7. Summary
Concept | Summary |
Tailwind | Utility-first, JIT-based CSS framework |
JIT Engine | Requires static class detection |
Dynamic Classes | Built using JS variables—ignored by JIT |
Safelist | Explicitly tells Tailwind which classes to keep |
Sitecore Integration | Token values per brand at runtime, injected into UI |
Final Thoughts
Tailwind CSS is a powerful framework, but like any tool, it has constraints. In CMS-driven, multi-brand enterprise applications like those built with Sitecore, dynamic styles can become a major bottleneck if not handled correctly.
By combining:
Token extraction from CMS
Safelisting dynamic Tailwind classes
You can unlock a highly scalable and maintainable architecture while keeping the benefits of Tailwind’s utility-first approach.
💬 Join the Conversation
Have you faced similar challenges working with Tailwind in multi-brand or CMS-driven environments like Sitecore?
Let’s exchange ideas, lessons, and solutions—connect with me on LinkedIn or drop a comment below.
Subscribe to my newsletter
Read articles from Karangiya Vraj directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Karangiya Vraj
Karangiya Vraj
Passionate Frontend Developer with 2.5 years of experience specializing in React.js and Next.js. Skilled in building responsive, user-friendly interfaces using Tailwind CSS. Enthusiastic about creating dynamic and engaging web applications.