225 lines
5.2 KiB
Markdown
225 lines
5.2 KiB
Markdown
# 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.
|
|
|
|
```css
|
|
: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.
|
|
|
|
```css
|
|
: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.
|
|
|
|
```css
|
|
: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:
|
|
|
|
```css
|
|
.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:
|
|
|
|
```css
|
|
/* === PRIMITIVES === */
|
|
:root { ... }
|
|
|
|
/* === SEMANTIC === */
|
|
:root { ... }
|
|
|
|
/* === COMPONENTS === */
|
|
:root { ... }
|
|
|
|
/* === DARK MODE === */
|
|
.dark { ... }
|
|
```
|
|
|
|
## Migration from Flat Tokens
|
|
|
|
Before (flat):
|
|
```css
|
|
--button-primary-bg: #2563EB;
|
|
--button-secondary-bg: #F3F4F6;
|
|
```
|
|
|
|
After (three-layer):
|
|
```css
|
|
/* 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):
|
|
|
|
```json
|
|
{
|
|
"color": {
|
|
"blue": {
|
|
"600": {
|
|
"$value": "#2563EB",
|
|
"$type": "color"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|