In large enterprise organizations supporting multiple digital products (web applications, native iOS/Android mobile clients, embeddable widgets, and internal admin consoles), misalignment between designers in Figma and frontend engineers leads to severe visual debt:
#3b82f6 vs #2563eb), arbitrary spacing offsets (ranging from 13px to 19px), and chaotic border radii.The architectural solution to this problem is Design Tokens.
An enterprise design token architecture relies on a strict three-tier hierarchy:
color.blue.500 = #3b82f6, space.4 = 16px).surface.canvas = var(--color-slate-950), color.interactive = var(--color-blue-500)).button.primary.bg = var(--color-interactive)).In Tailwind CSS v4, styling architecture transitioned to the native Rust-based Lightning CSS engine, completely deprecating tailwind.config.js in favor of the @theme directive and cascading CSS Custom Properties.
Components must never directly consume primitive tokens (such as bg-blue-500). They consume strictly semantic aliases (bg-brand-primary). In Tailwind v4, the @theme directive connects compiled Style Dictionary variables directly to utility classes with zero JavaScript configuration runtime overhead.
The token synchronization pipeline bridges the single source of truth in Figma with React components through an automated workflow:
┌─────────────────────────────────────────────────────────────┐
│ FIGMA DESIGN SYSTEM (Variables) │
│ Modes: Light / Dark / High Contrast / Tenant Brand │
└──────────────────────────────┬──────────────────────────────┘
│ Export via W3C Tokens Studio Plugin
▼
┌─────────────────────────────────────────────────────────────┐
│ DESIGN TOKENS REPOSITORY (DTCG JSON) │
│ tokens/primitives.json | tokens/semantic-dark.json │
└──────────────────────────────┬──────────────────────────────┘
│ Build via Style Dictionary v4
▼
┌─────────────────────────────────────────────────────────────┐
│ GENERATED CSS VARIABLES & TYPES │
│ dist/variables.css | dist/tokens.d.ts │
└──────────────────────────────┬──────────────────────────────┘
│ Injection into CSS Layer
▼
┌─────────────────────────────────────────────────────────────┐
│ TAILWIND CSS v4 (@theme directive) │
│ @theme { │
│ --color-canvas: var(--color-semantic-surface-canvas); │
│ --color-brand-primary: var(--color-semantic-brand); │
│ } │
└──────────────────────────────┬──────────────────────────────┘
│ Strict typing via CVA
▼
┌─────────────────────────────────────────────────────────────┐
│ REACT 19 TYPED UI COMPONENTS (Button, Card) │
│ <Button variant="primary" size="lg">Submit</Button> │
└─────────────────────────────────────────────────────────────┘Establish global colors, grid steps (4px/8px grid), and border radii in W3C DTCG JSON format.
Map semantic roles (surface, text, border, brand) bound to theme modes (Light, Dark, High-Contrast).
Generate CSS Custom Properties (variables.css) and TypeScript declaration files for the monorepo.
Import generated variables into the @theme directive inside your main globals.css stylesheet.
Build type-safe polymorphic components (Button, Card, Input) with support for the asChild prop.
Why is it strictly forbidden in an enterprise UI library to consume primitive tokens directly (such as className='bg-violet-500')?
Source tokens are authored in conformance with the Design Tokens Community Group specification:
{
"color": {
"primitive": {
"violet": {
"500": { "$value": "#8b5cf6", "$type": "color" },
"600": { "$value": "#7c3aed", "$type": "color" },
"900": { "$value": "#4c1d95", "$type": "color" }
},
"slate": {
"900": { "$value": "#0f172a", "$type": "color" },
"950": { "$value": "#020617", "$type": "color" }
}
},
"semantic": {
"surface": {
"canvas": {
"$value": "{color.primitive.slate.950}",
"$type": "color"
}
},
"brand": {
"primary": {
"$value": "{color.primitive.violet.500}",
"$type": "color"
},
"hover": {
"$value": "{color.primitive.violet.600}",
"$type": "color"
}
}
}
}
}The build configuration translates JSON tokens into CSS Custom Properties while maintaining reference integrity:
import StyleDictionary from 'style-dictionary';
const sd = new StyleDictionary({
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'src/tokens/dist/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: {
outputReferences: true, // Preserve var() cross-references between tokens
},
},
],
},
ts: {
transformGroup: 'js',
buildPath: 'src/tokens/dist/',
files: [
{
destination: 'tokens.ts',
format: 'javascript/es6',
},
{
destination: 'tokens.d.ts',
format: 'typescript/es6-declarations',
},
],
},
},
});
await sd.buildAllPlatforms();The generated CSS variables are imported and connected to the @theme directive in the application's root stylesheet:
@import "tailwindcss";
@import "../tokens/dist/variables.css";
/* Register design tokens into the Tailwind v4 utility engine */
@theme {
--color-canvas: var(--color-semantic-surface-canvas);
--color-brand-primary: var(--color-semantic-brand-primary);
--color-brand-hover: var(--color-semantic-brand-hover);
--font-sans: "Inter Variable", -apple-system, BlinkMacSystemFont, sans-serif;
--radius-badge: 0.375rem;
}
/* Theme overrides for Dark Mode */
:root[data-theme="dark"] {
--color-semantic-surface-canvas: #09090b;
--color-semantic-brand-primary: #a855f7;
--color-semantic-brand-hover: #9333ea;
}
/* Accessibility override for High Contrast Mode (WCAG AAA) */
:root[data-theme="high-contrast"] {
--color-semantic-surface-canvas: #000000;
--color-semantic-brand-primary: #ffff00;
--color-semantic-brand-hover: #ffffff;
}Designer adjusts brand accent in Figma. Plugin exports standardized DTCG tokens.json.
Validates token references and compiles variables.css and TypeScript tokens.d.ts.
Rust compiler derives utility classes (bg-brand-primary, text-canvas) from CSS variables.
Button component applies strict variant props (variant, size) typed via CVA.
How can you prevent Flash of Unstyled Theme (FOUT) during Server-Side Rendering in Next.js App Router?
Below is an enterprise-grade button component utilizing Tailwind v4 semantic tokens, class-variance-authority (CVA), and the Radix UI slot pattern (Slot / asChild) for type-safe polymorphism:
import React from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { Slot } from '@radix-ui/react-slot';
export const buttonVariants = cva(
// Base styles: layout, transitions, focus rings, accessibility
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
primary: 'bg-brand-primary text-white hover:bg-brand-hover shadow-sm',
secondary: 'bg-bg-elevated border border-border text-text-primary hover:bg-bg-elevated/80',
outline: 'border border-brand-primary/50 text-brand-primary hover:bg-brand-primary/10',
ghost: 'text-text-muted hover:text-text-primary hover:bg-bg-elevated/50',
danger: 'bg-danger text-white hover:bg-danger/90',
},
size: {
sm: 'h-8 px-3 text-xs',
md: 'h-10 px-4 py-2',
lg: 'h-12 px-6 text-base',
icon: 'h-10 w-10 p-0',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
/**
* When asChild=true, the component delegates styles and listeners to its first child (e.g. Next.js Link)
*/
asChild?: boolean;
}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Component = asChild ? Slot : 'button';
return (
<Component
className={buttonVariants({ variant, size, className })}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = 'Button';Using arbitrary utility overrides like className="bg-[#8b5cf6]" instead of semantic tokens className="bg-brand-primary". Such components remain blindingly purple in dark mode or high-contrast mode, breaking design system integrity.
// ❌ Anti-pattern: button fails to adjust when switching themes
<button className="bg-[#8b5cf6] text-white px-4 py-2">Save</button>
// ✅ Correct solution: semantic class bound to theme variables
<button className="bg-brand-primary text-white px-4 py-2">Save</button>Using primitive tokens directly inside components (e.g., bg-violet-500 instead of bg-brand-primary). If corporate rebranding shifts the primary identity from violet to emerald, thousands of files must be refactored instead of updating one line in the semantic token registry.
When the user's preferred theme is read from localStorage inside a client-side useEffect, the server always renders the light theme, and the client switches 100 ms later, causing an abrasive white flash.
Solution: Store theme choice in a cookie and set <html data-theme="..."> server-side during SSR, or inject a minimal blocking inline script in <head>.
Polymorphism via <Button as="a" href="/home"> compromises TypeScript type inference (TypeScript cannot determine which props are valid for button vs anchor). The asChild pattern powered by @radix-ui/react-slot ensures 100% type safety on the child target element.
tailwind.config.js with the native @theme directive powered by Lightning CSS in Rust.class-variance-authority) library guarantees end-to-end TypeScript safety across component variant permutations.asChild pattern via @radix-ui/react-slot ensures type-safe polymorphism while preserving semantic HTML contracts.