Design token architecture, component specifications, spacing/typography scales, and systematic design. Use when creating or documenting design tokens (primitive → semantic → component layers), configuring Tailwind themes, specifying component states/variants, setting up CSS variable systems, or producing design-to-code handoff documentation.
Covers design token systems, component specification patterns, and the three-layer token architecture used to build consistent, themeable UI.
┌─────────────────────────────────┐
│ Layer 1: Primitive Tokens │ Raw values — never used in components directly
│ --color-blue-600: #2563EB │
│ --size-4: 16px │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Layer 2: Semantic Tokens │ Purpose aliases — used in most components
│ --color-primary: var(--color-blue-600) │
│ --space-component: var(--size-4) │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Layer 3: Component Tokens │ Component-specific overrides
│ --button-bg: var(--color-primary) │
│ --button-padding: var(--space-component) │
└─────────────────────────────────┘
Rule: Components must only reference Layer 2 or Layer 3 tokens. Never hardcode primitives in component files.
/* Blue */
--color-blue-50: #EFF6FF;
--color-blue-100: #DBEAFE;
--color-blue-200: #BFDBFE;
--color-blue-300: #93C5FD;
--color-blue-400: #60A5FA;
--color-blue-500: #3B82F6;
--color-blue-600: #2563EB;
--color-blue-700: #1D4ED8;
--color-blue-800: #1E40AF;
--color-blue-900: #1E3A8A;
/* Neutral / Gray */
--color-gray-50: #F9FAFB;
--color-gray-100: #F3F4F6;
--color-gray-200: #E5E7EB;
--color-gray-300: #D1D5DB;
--color-gray-400: #9CA3AF;
--color-gray-500: #6B7280;
--color-gray-600: #4B5563;
--color-gray-700: #374151;
--color-gray-800: #1F2937;
--color-gray-900: #111827;
/* Semantic status primitives */
--color-red-600: #DC2626;
--color-green-600: #16A34A;
--color-yellow-500: #EAB308;
--space-0: 0px;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
--space-10: 40px;
--space-12: 48px;
--space-16: 64px;
--space-20: 80px;
--space-24: 96px;
--text-xs: 12px;
--text-sm: 14px;
--text-base: 16px;
--text-lg: 18px;
--text-xl: 20px;
--text-2xl: 24px;
--text-3xl: 30px;
--text-4xl: 36px;
--text-5xl: 48px;
--text-6xl: 60px;
/* Line heights */
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
:root {
/* Brand */
--color-primary: var(--color-blue-600);
--color-primary-hover: var(--color-blue-700);
--color-primary-pressed: var(--color-blue-800);
--color-secondary: var(--color-gray-600);
/* Surfaces */
--color-background: var(--color-gray-50);
--color-surface: #FFFFFF;
--color-surface-raised: #FFFFFF;
--color-overlay: rgba(0, 0, 0, 0.05);
/* Text */
--color-text-primary: var(--color-gray-900);
--color-text-secondary: var(--color-gray-600);
--color-text-muted: var(--color-gray-400);
--color-text-on-primary: #FFFFFF;
/* Borders */
--color-border: var(--color-gray-200);
--color-border-strong: var(--color-gray-400);
/* Status */
--color-error: var(--color-red-600);
--color-success: var(--color-green-600);
--color-warning: var(--color-yellow-500);
/* Spacing */
--space-xs: var(--space-1);
--space-sm: var(--space-2);
--space-md: var(--space-4);
--space-lg: var(--space-6);
--space-xl: var(--space-8);
--space-2xl: var(--space-12);
--space-section: var(--space-16);
/* Typography */
--font-heading: 'Inter', system-ui, sans-serif;
--font-body: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
/* Radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
--shadow-md: 0 4px 6px rgba(0,0,0,0.07);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.10);
--shadow-xl: 0 20px 25px rgba(0,0,0,0.12);
}
[data-theme="dark"] {
--color-primary: var(--color-blue-400); /* lighter for dark bg */
--color-primary-hover: var(--color-blue-300);
--color-background: var(--color-gray-900);
--color-surface: var(--color-gray-800);
--color-surface-raised: var(--color-gray-700);
--color-overlay: rgba(255,255,255,0.05);
--color-text-primary: var(--color-gray-50);
--color-text-secondary: var(--color-gray-300);
--color-text-muted: var(--color-gray-500);
--color-border: var(--color-gray-700);
--color-border-strong: var(--color-gray-500);
--shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
--shadow-md: 0 4px 6px rgba(0,0,0,0.4);
}
/* Primary Button */
--button-primary-bg: var(--color-primary);
--button-primary-bg-hover: var(--color-primary-hover);
--button-primary-bg-pressed: var(--color-primary-pressed);
--button-primary-text: var(--color-text-on-primary);
--button-primary-border: transparent;
/* Secondary Button */
--button-secondary-bg: transparent;
--button-secondary-bg-hover: var(--color-overlay);
--button-secondary-text: var(--color-text-primary);
--button-secondary-border: var(--color-border-strong);
/* Dimensions */
--button-height-sm: 32px;
--button-height-md: 40px;
--button-height-lg: 48px;
--button-padding-x: var(--space-md);
--button-radius: var(--radius-md);
--input-bg: var(--color-surface);
--input-bg-focus: var(--color-surface);
--input-border: var(--color-border);
--input-border-focus: var(--color-primary);
--input-border-error: var(--color-error);
--input-text: var(--color-text-primary);
--input-placeholder: var(--color-text-muted);
--input-height: 40px;
--input-radius: var(--radius-md);
--input-padding-x: var(--space-md);
--card-bg: var(--color-surface);
--card-border: var(--color-border);
--card-shadow: var(--shadow-md);
--card-radius: var(--radius-lg);
--card-padding: var(--space-lg);
| State | Background | Text | Border | Shadow | Opacity |
|---|---|---|---|---|---|
| Default | --color-primary | white | none | --shadow-sm | 1 |
| Hover | --color-primary-hover | white | none | --shadow-md | 1 |
| Active/Pressed | --color-primary-pressed | white | none | none | 1 |
| Focused | --color-primary | white | 2px ring | --shadow-md | 1 |
| Disabled | --color-primary | white | none | none | 0.4 |
| Loading | --color-primary | white (spinner) | none | none | 0.8 |
module.exports = {
theme: {
extend: {
colors: {
primary: {
DEFAULT: 'var(--color-primary)',
hover: 'var(--color-primary-hover)',
pressed: 'var(--color-primary-pressed)',
},
surface: 'var(--color-surface)',
background: 'var(--color-background)',
border: 'var(--color-border)',
text: {
primary: 'var(--color-text-primary)',
secondary: 'var(--color-text-secondary)',
muted: 'var(--color-text-muted)',
},
},
borderRadius: {
sm: 'var(--radius-sm)',
md: 'var(--radius-md)',
lg: 'var(--radius-lg)',
},
boxShadow: {
sm: 'var(--shadow-sm)',
md: 'var(--shadow-md)',
lg: 'var(--shadow-lg)',
},
fontFamily: {
sans: 'var(--font-body)',
heading: 'var(--font-heading)',
mono: 'var(--font-mono)',
},
},
},
};
| Name | Value | Use |
|---|---|---|
space-xs | 4px | Inline gap, icon padding |
space-sm | 8px | Input padding, list item gap |
space-md | 16px | Component internal padding |
space-lg | 24px | Card padding, section gap within component |
space-xl | 32px | Between components on a page |
space-2xl | 48px | Between major sections |
space-section | 64px | Between page-level sections |
brand (color and typography primitives)ui-styling (Tailwind config, shadcn/ui theming), all UI components