Tailwind CSS utility generation vs runtime‑composed class names: safelist or source refactor
0 reputation · 11 Feb 2022, 14:06 UTC
0 reputation · 11 Feb 2022, 14:06 UTC
Ensure that every utility class needed at runtime appears in the production CSS even when class names are assembled dynamically, such as via string concatenation in JavaScript templates.
Tailwind’s content scan only detects literal class names in configured files; dynamically built strings are ignored unless explicitly safelisted. Adding safelist entries guarantees generation but introduces configuration overhead, while refactoring to literal names eliminates the need for safelist but may require code changes.
34775 reputation · 11 Feb 2022, 20:55 UTC
When you control the source of the class string, refactor to literal names. Keep the safelist minimal for truly external markup (CMS, third‑party HTML). This split keeps the build lean, preserves linting, and makes intent visible.
Literal class names stay in the template, so the visual intent is immediately obvious. A small refactor – for example, a variant map – can replace concatenation without changing the UI:
const variantClasses = {
danger: 'bg-red-500 text-white',
success: 'bg-green-500 text-white',
};
<div className={variantClasses[tone]}>…</div>
In contrast, a safelist decouples usage from generation. Removing the last consumer of a safelisted class leaves the utility in the CSS forever unless the config is updated, which can lead to bloated stylesheets.
tailwind.config.js file, a direct input to the compiler. Any edit forces a full CSS rebuild and invalidates the cache, even if no template changed.Both produce the same final CSS for the same inputs, but the refactor path yields finer‑grained cache hits and smaller bundles.
ESLint plugins, Stylelint, and Tailwind CSS IntelliSense only understand literal strings. Safelisted patterns are invisible to these tools, so autocomplete and typo detection are lost. If your team already enforces utility‑class rules, literal names stay in sync with the linting configuration.
text-emerald-600) or a tight regex (bg-(red|green)-500).npx tailwindcss -o dist/output.css and grep -c '\\.bg-' dist/output.css before and after changes.eslint-plugin-tailwindcss rule no-custom-classname to catch any remaining dynamic patterns.npm run build -- --verbose.Use safelist only when you cannot touch the source of the class string. For all other cases, refactor to literal names; it keeps the codebase maintainable, the build cache efficient, and the linting ecosystem happy.
Do any of your runtime‑composed classes originate from content you cannot control (e.g., CMS fields or external HTML)? If so, a safelist is unavoidable.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.