5.2 KiB
5.2 KiB
Token Architecture
Three-layer token system for scalable, themeable design systems.
Layer Overview
┌─────────────────────────────────────────┐
│ Component Tokens │ Per-component overrides
│ --button-bg, --card-padding │
├─────────────────────────────────────────┤
│ Semantic Tokens │ Purpose-based aliases
│ --color-primary, --spacing-section │
├─────────────────────────────────────────┤
│ Primitive Tokens │ Raw design values
│ --color-blue-600, --space-4 │
└─────────────────────────────────────────┘
Why Three Layers?
| Layer | Purpose | When to Change |
|---|---|---|
| Primitive | Base values (colors, sizes) | Rarely - foundational |
| Semantic | Meaning assignment | Theme switching |
| Component | Component customization | Per-component needs |
Layer 1: Primitive Tokens
Raw design values without semantic meaning.
:root {
/* Colors */
--color-gray-50: #F9FAFB;
--color-gray-900: #111827;
--color-blue-500: #3B82F6;
--color-blue-600: #2563EB;
/* Spacing (4px base) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
/* Typography */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
/* Radius */
--radius-sm: 0.25rem;
--radius-default: 0.5rem;
--radius-lg: 0.75rem;
/* Shadows */
--shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
--shadow-default: 0 1px 3px rgb(0 0 0 / 0.1);
}
Layer 2: Semantic Tokens
Purpose-based aliases that reference primitives.
:root {
/* Background */
--color-background: var(--color-gray-50);
--color-foreground: var(--color-gray-900);
/* Primary */
--color-primary: var(--color-blue-600);
--color-primary-hover: var(--color-blue-700);
/* Secondary */
--color-secondary: var(--color-gray-100);
--color-secondary-foreground: var(--color-gray-900);
/* Muted */
--color-muted: var(--color-gray-100);
--color-muted-foreground: var(--color-gray-500);
/* Destructive */
--color-destructive: var(--color-red-600);
--color-destructive-foreground: white;
/* Spacing */
--spacing-component: var(--space-4);
--spacing-section: var(--space-6);
}
Layer 3: Component Tokens
Component-specific tokens referencing semantic layer.
:root {
/* Button */
--button-bg: var(--color-primary);
--button-fg: white;
--button-hover-bg: var(--color-primary-hover);
--button-padding-x: var(--space-4);
--button-padding-y: var(--space-2);
--button-radius: var(--radius-default);
/* Input */
--input-bg: var(--color-background);
--input-border: var(--color-gray-300);
--input-focus-ring: var(--color-primary);
--input-padding: var(--space-2) var(--space-3);
/* Card */
--card-bg: var(--color-background);
--card-border: var(--color-gray-200);
--card-padding: var(--space-4);
--card-radius: var(--radius-lg);
--card-shadow: var(--shadow-default);
}
Dark Mode
Override semantic tokens for dark theme:
.dark {
--color-background: var(--color-gray-900);
--color-foreground: var(--color-gray-50);
--color-muted: var(--color-gray-800);
--color-muted-foreground: var(--color-gray-400);
--color-secondary: var(--color-gray-800);
}
Naming Convention
--{category}-{item}-{variant}-{state}
Examples:
--color-primary # category-item
--color-primary-hover # category-item-state
--button-bg-hover # component-property-state
--space-section-sm # category-semantic-variant
Categories
| Category | Examples |
|---|---|
| color | primary, secondary, muted, destructive |
| space | 1, 2, 4, 8, section, component |
| font-size | xs, sm, base, lg, xl |
| radius | sm, default, lg, full |
| shadow | sm, default, lg |
| duration | fast, normal, slow |
File Organization
tokens/
├── primitives.css # Raw values
├── semantic.css # Purpose aliases
├── components.css # Component tokens
└── index.css # Imports all
Or single file with layer comments:
/* === PRIMITIVES === */
:root { ... }
/* === SEMANTIC === */
:root { ... }
/* === COMPONENTS === */
:root { ... }
/* === DARK MODE === */
.dark { ... }
Migration from Flat Tokens
Before (flat):
--button-primary-bg: #2563EB;
--button-secondary-bg: #F3F4F6;
After (three-layer):
/* Primitive */
--color-blue-600: #2563EB;
--color-gray-100: #F3F4F6;
/* Semantic */
--color-primary: var(--color-blue-600);
--color-secondary: var(--color-gray-100);
/* Component */
--button-bg: var(--color-primary);
--button-secondary-bg: var(--color-secondary);
W3C DTCG Alignment
Token JSON format (W3C Design Tokens Community Group):
{
"color": {
"blue": {
"600": {
"$value": "#2563EB",
"$type": "color"
}
}
}
}