Efficiently Manage Dynamic Tailwind CSS with Safelist & Theming

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.
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
safelistfeature 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
safelistin 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
safelistarray in yourtailwind.config.jsallows 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.


