Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/tailwind-dynamic-class-generation.md
1# Tailwind CSS Dynamic Class Generation23## Rule45Never construct Tailwind CSS class names dynamically using string concatenation or template literals. Tailwind's build process cannot detect dynamically generated class names, causing styles to be missing in production.67## Why This Matters89- Tailwind uses static analysis at build time to determine which CSS classes to include10- Dynamically constructed class names (e.g., `bg-${color}-500`) are invisible to Tailwind's scanner11- Classes work in development with JIT but fail silently in production builds12- This is a common source of "it works locally but not in production" bugs1314## Bad Code1516```vue17<script setup>18const props = defineProps({19color: String, // 'red', 'blue', 'green'20size: String // 'sm', 'md', 'lg'21})22</script>2324<template>25<!-- WRONG: Tailwind cannot detect these classes -->26<div :class="`bg-${color}-500 text-${size}`">27Content28</div>2930<!-- WRONG: String concatenation -->31<div :class="'p-' + padding">32Content33</div>3435<!-- WRONG: Template literal in array -->36<div :class="[`gap-x-${spacing}`]">37Content38</div>39</template>40```4142## Good Code4344```vue45<script setup>46const props = defineProps({47color: String,48size: String49})5051// Use a mapping object with complete class names52const colorClasses = {53red: 'bg-red-500',54blue: 'bg-blue-500',55green: 'bg-green-500'56}5758const sizeClasses = {59sm: 'text-sm p-2',60md: 'text-base p-4',61lg: 'text-lg p-6'62}63</script>6465<template>66<!-- CORRECT: Full class names that Tailwind can detect -->67<div :class="[colorClasses[color], sizeClasses[size]]">68Content69</div>70</template>71```7273## Using Conditional Objects7475```vue76<script setup>77const props = defineProps({78variant: String // 'primary', 'secondary', 'danger'79})80</script>8182<template>83<!-- CORRECT: All class names are complete strings -->84<button :class="{85'bg-blue-500 hover:bg-blue-600': variant === 'primary',86'bg-gray-500 hover:bg-gray-600': variant === 'secondary',87'bg-red-500 hover:bg-red-600': variant === 'danger'88}">89Click me90</button>91</template>92```9394## Safelist for Truly Dynamic Classes9596If you must use dynamic classes, add them to Tailwind's safelist:9798```javascript99// tailwind.config.js100module.exports = {101safelist: [102'bg-red-500',103'bg-blue-500',104'bg-green-500',105// Or use patterns (use sparingly - increases bundle size)106{107pattern: /bg-(red|blue|green)-(100|500|900)/108}109]110}111```112113## Alternative: CSS Custom Properties114115For truly dynamic values, use CSS custom properties:116117```vue118<script setup>119const props = defineProps({120customColor: String // Any hex color121})122</script>123124<template>125<!-- Use CSS variable for truly dynamic values -->126<div127class="dynamic-bg"128:style="{ '--dynamic-color': customColor }"129>130Content131</div>132</template>133134<style>135.dynamic-bg {136background-color: var(--dynamic-color);137}138</style>139```140141## References142143- [Tailwind CSS Dynamic Class Names](https://tailwindcss.com/docs/content-configuration#dynamic-class-names)144- [Tailwind Safelist](https://tailwindcss.com/docs/content-configuration#safelisting-classes)145