March 2, 2026
Design Tokens That Scale with Tailwind CSS v4
Tailwind CSS v4 moved configuration into CSS itself, and that changes how you should think about design tokens. Instead of a JavaScript config file, your tokens live where they belong — in the cascade.
Semantic tokens over raw values
The mistake most teams make is exposing raw palette values (zinc-100,
amber-600) directly to components. Instead, define semantic tokens and map
them per theme:
:root {
--background: #fdfdfc;
--foreground: #18181b;
--accent: #b45309;
}
.dark {
--background: #0a0a0a;
--foreground: #f4f4f5;
--accent: #fbbf24;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-accent: var(--accent);
}Now bg-background, text-foreground, and text-accent work everywhere —
and dark mode is a single class toggle, not a dark: variant sprinkled
across every component.
Custom variants for class-based dark mode
If you drive dark mode with a class (via next-themes or similar), tell
Tailwind about it:
@custom-variant dark (&:where(.dark, .dark *));This keeps dark: variants working for the rare cases where a semantic
token isn't enough.
The rule of thumb
If you find yourself writing the same dark: override twice, it should be a
semantic token. Components should describe roles — surface, border, muted —
never colors.