Why Design Tokens Matter
Tailwind v4 @theme on this TanStack Start site — what to share, what to leave local, and when a token is not worth it.
Design tokens name colors, type, spacing, radius, and shadow once. On a personal site the win is restyle without grepping the whole repo — not an enterprise design system.
Before tokens
A color change meant hunting one-off utility strings. A type tweak meant deciding every body class by hand. Tokens point utilities at one definition. Markup still looks like Tailwind; values resolve to shared CSS variables.
Tailwind v4 @theme
Tokens live in src/styles.css next to the rest of the system:
@theme {
--color-sky-tint: #ebf5ff;
--color-ink: #0a0d12;
--font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif;
--radius-xl: 12px;
}
Tailwind generates bg-sky-tint, text-ink, rounded-xl. Redesign becomes a token list edit, not a scattered class rewrite.
Subtlety: day-cycle sky colors remapped via [data-day-luma] must use plain @theme, not @theme inline. inline bakes hex into utilities so runtime overrides never apply. Plain @theme keeps var(--color-*) so contrast can flip with the sky.
Practical limits
Tokenize values used three or more times, or likely to change. One-off colors, radii, or shadows do not need a name. If you cannot name a token without a paragraph of context, leave it local.
This site keeps a small set — surfaces, text steps, focus, a few radii and shadows (DESIGN.md). Most UI uses a handful. That ratio is the test.
Migration order that worked
- Inventory colors and type sizes used more than twice.
- Move into
@themewith boring names (ink,graphite,dusk-violet). - Replace utilities section by section — not one unreviewable commit.
- Leave true one-offs until they repeat.
Then sky or tracking is a single edit. Components stay ordinary Tailwind + shadcn/ui. Tokens cut thrash; they should not invent a second styling language.