ESC

Type to search the knowledge base.

Design a Design System

System design for a design system — tokens, components, versioning, adoption, a11y, and multi-platform tradeoffs.

intermediate4 min read
  • system-design
  • interview
  • architecture
  • design-system

Scope the problem

In scope:

  • Foundations (tokens, typography, space, color)
  • Component library architecture
  • Documentation and playground
  • Versioning and release
  • Adoption across teams
  • Accessibility and theming

Out of scope: full Figma org process deep dive (mention partnership), native iOS/Android UIKit parity details unless asked.

Goals

Goal Signal
Consistency fewer one-off UI primitives
Velocity features compose existing components
Quality a11y + responsive defaults baked in
Safe change semantic versioning; codemods when needed

Layered architecture

┌─────────────────────────────────────────┐
│ Products / features                     │
├─────────────────────────────────────────┤
│ Pattern library (Form layout, Page H1)  │
├─────────────────────────────────────────┤
│ Components (Button, Modal, Table…)      │
├─────────────────────────────────────────┤
│ Primitives (Box, Text, Stack)            │
├─────────────────────────────────────────┤
│ Tokens (CSS vars / JS)                  │
└─────────────────────────────────────────┘

Lower layers change rarely and carefully; products should depend downward, not sideways into other products’ CSS.

Tokens

:root {
  --color-bg: #fff;
  --color-fg: #111;
  --color-brand-600: #2563eb;
  --space-1: 4px;
  --space-2: 8px;
  --radius-md: 8px;
  --font-sans: "Inter", system-ui, sans-serif;
  --focus-ring: 0 0 0 3px Highlight;
}

[data-theme="dark"] {
  --color-bg: #0b0b0c;
  --color-fg: #f5f5f5;
}

Rules:

  • Semantic tokens (--color-danger-fg) map to core palettes
  • No hard-coded hex in feature code
  • Density themes via space scale aliases

Component API design

type ButtonProps = {
  variant?: "primary" | "secondary" | "ghost" | "danger";
  size?: "sm" | "md" | "lg";
  loading?: boolean;
  disabled?: boolean;
  leftIcon?: React.ReactNode;
  children: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

Principles:

  • Prefer composition (Modal.Title) over 40 boolean props
  • Polymorphic asChild / as sparingly
  • Accessibility props required where needed (IconButton + aria-label)
  • Style escape hatch: className + documented CSS variables, not deep override soup

Packaging & monorepo

packages/
  tokens/
  react/
  css/
  docs/
  • Build with preserved modules for tree-shaking
  • Side-effect free entry; CSS import path explicit
  • Peer deps on React

Versioning

Change Version
New optional prop / component minor
Token rename with alias minor then deprecate
Remove prop / change default visuals breaking layouts major
A11y fix without API change patch

Provide codemods for majors. Deprecation window communicated in docs + lint rules.

Documentation

  • Storybook (or similar) with a11y addon
  • Do/Don’t guidance
  • Copy-paste examples
  • Migration guides

Adoption dies without docs; treat docs as product surface.

Theming & brands (multi-tenant)

  • Token packs per brand loaded at runtime or build
  • Components read CSS variables only
  • Avoid branching component logic per customer — data-drive tokens

Governance

  1. RFC for new components
  2. Design + eng dual ownership
  3. Contribution model: fix in system > local fork
  4. Lint: ban raw <button> in apps if Button exists (optional gradual)

Performance

  • Tree-shakeable ESM
  • Avoid barrel files that re-export everything eagerly if bundler is weak
  • Icons as individual imports
  • CSS size budget; prefer CSS variables over large runtime style engines if SSR is critical (or accept tradeoffs of CSS-in-JS)

Accessibility bar

  • Every interactive component has keyboard + APG behavior tests
  • Contrast checked against token pairs
  • Focus visible by default

Tradeoffs

  1. Flexibility vs consistency — too rigid and teams fork; too loose and system dies
  2. CSS-in-JS vs CSS modules/variables — DX vs perf/SSR
  3. Multi-platform one API vs specialized packages
  4. Big bang redesign vs incremental token migration

Rollout plan

  1. Tokens + 10 highest-traffic components
  2. Pilot one product team
  3. Codemod + lint
  4. Expand patterns
  5. Measure adoption (% of UI imports from system)

Interview close

Layers tokens → components → patterns; versioning and docs; a11y defaults; adoption strategy. Mention what you refuse (one-off modals) and how dark theme works via tokens.

Further reading