Design System
Establish the visual language of the application through design tokens, typography scales, and spacing systems before components are built.
A design system is the single source of truth for the visual language of an application. It defines the building blocks that every component is constructed from. Without it, every developer makes independent styling decisions that accumulate into an incoherent, unmaintainable interface.
Design Tokens
Design tokens are named variables that store design decisions. They are the mechanism that makes a design system consistent, themeable, and maintainable. Every color, spacing value, font size, and animation duration that appears more than once in the codebase should be a token.
Tokens exist at two levels: primitive tokens (the raw values) and semantic tokens (tokens that reference primitives and carry meaning). Only semantic tokens should appear in component code.
/* globals.css */
:root {
/* Primitive tokens — raw values, rarely used directly */
--zinc-50: #fafafa;
--zinc-100: #f4f4f5;
--zinc-200: #e4e4e7;
--zinc-500: #71717a;
--zinc-900: #18181b;
--zinc-950: #09090b;
--blue-500: #3b82f6;
--blue-600: #2563eb;
--red-500: #ef4444;
--green-500:#22c55e;
/* Semantic tokens — reference primitives, carry intent */
--color-background: var(--zinc-50);
--color-foreground: var(--zinc-950);
--color-border: var(--zinc-200);
--color-muted: var(--zinc-100);
--color-muted-fg: var(--zinc-500);
--color-primary: var(--zinc-900);
--color-primary-fg: var(--zinc-50);
--color-destructive: var(--red-500);
--color-success: var(--green-500);
--color-info: var(--blue-500);
}Never reference primitive tokens in component code. See Dark Mode & Theming for the full token architecture, system detection implementation, and dark mode testing strategy. Write bg-background, not bg-zinc-50. When you add dark mode or a white-label theme, you change only the semantic token values — all components update automatically.
Color System
A functional color system has four categories. Each category maps to a semantic purpose, not a visual color.
| Category | Tokens | Used for |
|---|---|---|
| Neutrals | background, foreground, muted, muted-fg, border | Page backgrounds, body text, dividers, placeholder text |
| Brand | primary, primary-fg | Primary call-to-action buttons, active states, key highlights |
| Semantic | destructive, success, warning, info | Validation errors, success confirmations, warning notices |
| Surface | card, popover, sidebar | Elevated surfaces, overlays, distinct content regions |
Contrast requirements
Every foreground/background color pair must meet WCAG 2.1 AA contrast ratios. This is a functional requirement, not an aesthetic preference.
| Text type | Minimum ratio | Enhanced (AAA) |
|---|---|---|
| Normal text (under 18px) | 4.5 : 1 | 7 : 1 |
| Large text (18px+ or 14px+ bold) | 3 : 1 | 4.5 : 1 |
| UI components and graphical objects | 3 : 1 | — |
Typography Scale
Use a modular type scale — a set of sizes based on a consistent ratio — rather than arbitrary font sizes chosen per component. A common scale uses a ratio of 1.25 (Major Third) or 1.333 (Perfect Fourth).
@theme inline {
/* Font families */
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'Geist Mono', ui-monospace, monospace;
/* Type scale — Major Third (×1.25) */
--text-xs: 0.64rem; /* 10.24px — labels, captions */
--text-sm: 0.8rem; /* 12.8px — secondary body, table cells */
--text-base: 1rem; /* 16px — primary body text */
--text-lg: 1.25rem; /* 20px — lead paragraphs, card titles */
--text-xl: 1.563rem; /* 25px — section headings (h3) */
--text-2xl: 1.953rem; /* 31px — page headings (h2) */
--text-3xl: 2.441rem; /* 39px — hero headings (h1) */
--text-4xl: 3.052rem; /* 49px — display headings */
/* Line heights */
--leading-tight: 1.25; /* Headings */
--leading-snug: 1.375; /* Sub-headings */
--leading-normal: 1.5; /* Body text */
--leading-relaxed:1.625; /* Long-form content */
}Usage rules
- Body text must never be below
14px(0.875rem) for readability - Use maximum 2 font families per application — one for UI, one for monospace code
- Line length (measure) for body text: 60–80 characters. Use
max-w-proseormax-w-2xl - Heading hierarchy must be sequential: no skipping from H1 to H3
- Font weight: use 400 (regular) for body, 500–600 (medium/semibold) for UI labels, 700 (bold) for headings
Spacing System
All spacing — margin, padding, gap — must come from a predefined scale. Tailwind CSS provides a 4px-base scale (1 = 4px) which maps to p-1 through p-96. Use this scale exclusively. Arbitrary values like p-[13px] are a sign that the design does not align with the spacing system.
| Token | px value | Common use |
|---|---|---|
| space-1 (4px) | 4px | Icon-to-label gap, tight inline spacing |
| space-2 (8px) | 8px | Between related items within a component |
| space-3 (12px) | 12px | Internal component padding |
| space-4 (16px) | 16px | Standard component padding, stack gaps |
| space-6 (24px) | 24px | Section internal spacing |
| space-8 (32px) | 32px | Between components on a page |
| space-12 (48px) | 48px | Between major sections |
| space-16 (64px) | 64px | Page-level vertical rhythm |
Breakpoints
Define breakpoints based on content needs, not device names. The goal is for content to look right at every width, not to target specific devices.
/* Tailwind v4 default — extend as needed */
--breakpoint-sm: 640px; /* Minimum: large phones landscape */
--breakpoint-md: 768px; /* Tablets */
--breakpoint-lg: 1024px; /* Small laptops */
--breakpoint-xl: 1280px; /* Standard desktops */
--breakpoint-2xl: 1536px; /* Wide screens */
/* Usage in components — always mobile-first */
className="flex-col md:flex-row"
className="text-sm lg:text-base"
className="grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"Motion & Transitions
Define animation durations and easing functions as tokens. Consistent motion creates a sense of physical cohesion across the interface. Inconsistent durations make the UI feel assembled from parts.
:root {
/* Durations */
--duration-instant: 50ms; /* Feedback: hover, focus rings */
--duration-fast: 100ms; /* Small element entrances */
--duration-moderate: 200ms; /* Most UI transitions: modals, drawers */
--duration-slow: 400ms; /* Large-area transitions, page changes */
/* Easing */
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1); /* Elements entering view */
--ease-in: cubic-bezier(0.4, 0.0, 1, 1); /* Elements leaving view */
--ease-inout: cubic-bezier(0.4, 0.0, 0.2, 1); /* Position changes */
}Always respect the prefers-reduced-motion media query. Users who have requested reduced motion should not be subjected to animations. Wrap all motion in @media (prefers-reduced-motion: no-preference) or use the Tailwind motion-safe: variant.
Token Naming Conventions
Token names must be semantic and role-based, not value-based. A token named --color-blue-500 cannot be repurposed without renaming it. A token named --color-interactive can be changed from blue to any color without touching any component code.
| Bad (value-based) | Good (semantic) | Reason |
|---|---|---|
--color-gray-100 | --color-background-subtle | Describes purpose, not shade |
--color-blue-600 | --color-primary | Can be rebranded without renaming |
--font-size-14 | --text-sm | Scale-relative, not pixel-dependent |
--spacing-16px | --space-4 | Abstracted from specific px value |
--border-gray | --border-default | Context-independent |
AI agents can generate the complete token file from a design specification. Provide your brand colours, type scale ratio, and spacing base, and ask for a full globals.css with primitive tokens, semantic tokens, and dark mode overrides. Agents can also generate TypeScript token type definitions for compile-time safety. Always verify dark mode contrast ratios — this is the most common gap in agent-generated tokens.
Responsive Design
Strategy, patterns, and testing for interfaces that adapt across devices — breakpoints, fluid typography, layout patterns, touch, images, and responsive testing.
Design System Governance
Evolve your design system without breaking products — token versioning, component deprecation, change logs, and patterns for managing systems across multiple products.