How to Create Design Tokens¶
This guide walks you through defining a design token system for your project.
Prerequisites¶
- A design direction (colors, fonts chosen)
- Understanding of CSS custom properties
- Access to your project's CSS
Steps¶
1. Define Primitive Color Tokens¶
Start with your raw color values:
:root {
/* Neutral palette */
--gray-50: #f8fafc;
--gray-100: #f1f5f9;
--gray-200: #e2e8f0;
--gray-300: #cbd5e1;
--gray-400: #94a3b8;
--gray-500: #64748b;
--gray-600: #475569;
--gray-700: #334155;
--gray-800: #1e293b;
--gray-900: #0f172a;
/* Brand colors */
--blue-50: #eff6ff;
--blue-100: #dbeafe;
--blue-500: #3b82f6;
--blue-600: #2563eb;
--blue-700: #1d4ed8;
/* Semantic colors */
--red-500: #ef4444;
--yellow-500: #eab308;
--green-500: #22c55e;
}
2. Create Semantic Color Tokens¶
Map primitives to meaningful names:
:root {
/* Text colors */
--color-text: var(--gray-900);
--color-text-muted: var(--gray-500);
--color-text-inverse: white;
/* Background colors */
--color-background: white;
--color-surface: var(--gray-50);
--color-surface-raised: white;
/* Border colors */
--color-border: var(--gray-200);
--color-border-muted: var(--gray-100);
/* Interactive colors */
--color-primary: var(--blue-500);
--color-primary-hover: var(--blue-600);
--color-primary-active: var(--blue-700);
/* Status colors */
--color-success: var(--green-500);
--color-warning: var(--yellow-500);
--color-error: var(--red-500);
/* Focus */
--color-focus: var(--blue-500);
}
3. Define Spacing Tokens¶
Use a consistent base unit (typically 4px or 8px):
:root {
/* Base: 4px */
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
--space-24: 6rem; /* 96px */
}
4. Define Typography Tokens¶
:root {
/* Font families */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'Fira Code', 'Consolas', monospace;
/* Font sizes */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
--text-4xl: 2.25rem; /* 36px */
/* Font weights */
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
/* Line heights */
--leading-none: 1;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
}
5. Define Effect Tokens¶
:root {
/* Border radius */
--radius-none: 0;
--radius-sm: 0.25rem; /* 4px */
--radius-md: 0.375rem; /* 6px */
--radius-lg: 0.5rem; /* 8px */
--radius-xl: 0.75rem; /* 12px */
--radius-2xl: 1rem; /* 16px */
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
/* Transitions */
--duration-fast: 100ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
}
6. Define Z-Index Scale¶
:root {
--z-base: 0;
--z-dropdown: 1000;
--z-sticky: 1100;
--z-modal-backdrop: 1200;
--z-modal: 1300;
--z-popover: 1400;
--z-tooltip: 1500;
}
7. Add Dark Theme (Optional)¶
[data-theme="dark"] {
/* Text colors */
--color-text: var(--gray-100);
--color-text-muted: var(--gray-400);
/* Background colors */
--color-background: var(--gray-900);
--color-surface: var(--gray-800);
--color-surface-raised: var(--gray-700);
/* Border colors */
--color-border: var(--gray-700);
--color-border-muted: var(--gray-800);
/* Adjust shadows for dark mode */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4);
}
8. Create Component Tokens (Optional)¶
For frequently-used component values:
:root {
/* Button */
--button-padding-x: var(--space-4);
--button-padding-y: var(--space-2);
--button-radius: var(--radius-md);
--button-font-weight: var(--font-medium);
/* Card */
--card-padding: var(--space-4);
--card-radius: var(--radius-lg);
--card-shadow: var(--shadow-md);
/* Input */
--input-padding-x: var(--space-3);
--input-padding-y: var(--space-2);
--input-radius: var(--radius-md);
--input-border-color: var(--color-border);
}
9. Document Your Tokens¶
Create a reference showing all tokens and their values:
## Color Tokens
| Token | Light | Dark |
|-------|-------|------|
| --color-text | gray-900 | gray-100 |
| --color-background | white | gray-900 |
...
10. Use Tokens in Components¶
.button {
padding: var(--button-padding-y) var(--button-padding-x);
border-radius: var(--button-radius);
font-weight: var(--button-font-weight);
background: var(--color-primary);
color: var(--color-text-inverse);
transition: background var(--duration-fast) var(--ease-default);
}
.button:hover {
background: var(--color-primary-hover);
}
.button:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
Token Naming Checklist¶
- Names describe purpose, not value (
--color-primarynot--blue) - Consistent naming convention (CTI: category-type-item)
- Primitive tokens are context-free
- Semantic tokens are meaningful
- Component tokens reference semantic tokens
Common Mistakes¶
| Mistake | Problem | Fix |
|---|---|---|
| Values in component CSS | Changes require hunting | Use tokens everywhere |
| Primitives in components | Coupling to specific values | Use semantic tokens |
| Too many tokens | Hard to maintain | Start small, add as needed |
| Inconsistent naming | Confusing to use | Establish convention |
Related¶
- Design Tokens — Background on token theory
- Design Tokens Reference — Complete token list