Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.1 KiB
3.1 KiB
Tailwind CSS Dynamic Class Generation
Rule
Never 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.
Why This Matters
- Tailwind uses static analysis at build time to determine which CSS classes to include
- Dynamically constructed class names (e.g.,
bg-${color}-500) are invisible to Tailwind's scanner - Classes work in development with JIT but fail silently in production builds
- This is a common source of "it works locally but not in production" bugs
Bad Code
<script setup>
const props = defineProps({
color: String, // 'red', 'blue', 'green'
size: String // 'sm', 'md', 'lg'
})
</script>
<template>
<!-- WRONG: Tailwind cannot detect these classes -->
<div :class="`bg-${color}-500 text-${size}`">
Content
</div>
<!-- WRONG: String concatenation -->
<div :class="'p-' + padding">
Content
</div>
<!-- WRONG: Template literal in array -->
<div :class="[`gap-x-${spacing}`]">
Content
</div>
</template>
Good Code
<script setup>
const props = defineProps({
color: String,
size: String
})
// Use a mapping object with complete class names
const colorClasses = {
red: 'bg-red-500',
blue: 'bg-blue-500',
green: 'bg-green-500'
}
const sizeClasses = {
sm: 'text-sm p-2',
md: 'text-base p-4',
lg: 'text-lg p-6'
}
</script>
<template>
<!-- CORRECT: Full class names that Tailwind can detect -->
<div :class="[colorClasses[color], sizeClasses[size]]">
Content
</div>
</template>
Using Conditional Objects
<script setup>
const props = defineProps({
variant: String // 'primary', 'secondary', 'danger'
})
</script>
<template>
<!-- CORRECT: All class names are complete strings -->
<button :class="{
'bg-blue-500 hover:bg-blue-600': variant === 'primary',
'bg-gray-500 hover:bg-gray-600': variant === 'secondary',
'bg-red-500 hover:bg-red-600': variant === 'danger'
}">
Click me
</button>
</template>
Safelist for Truly Dynamic Classes
If you must use dynamic classes, add them to Tailwind's safelist:
// tailwind.config.js
module.exports = {
safelist: [
'bg-red-500',
'bg-blue-500',
'bg-green-500',
// Or use patterns (use sparingly - increases bundle size)
{
pattern: /bg-(red|blue|green)-(100|500|900)/
}
]
}
Alternative: CSS Custom Properties
For truly dynamic values, use CSS custom properties:
<script setup>
const props = defineProps({
customColor: String // Any hex color
})
</script>
<template>
<!-- Use CSS variable for truly dynamic values -->
<div
class="dynamic-bg"
:style="{ '--dynamic-color': customColor }"
>
Content
</div>
</template>
<style>
.dynamic-bg {
background-color: var(--dynamic-color);
}
</style>