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/assparingly - 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
- RFC for new components
- Design + eng dual ownership
- Contribution model: fix in system > local fork
- 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
- Flexibility vs consistency — too rigid and teams fork; too loose and system dies
- CSS-in-JS vs CSS modules/variables — DX vs perf/SSR
- Multi-platform one API vs specialized packages
- Big bang redesign vs incremental token migration
Rollout plan
- Tokens + 10 highest-traffic components
- Pilot one product team
- Codemod + lint
- Expand patterns
- 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.
Related on this site
- Accessibility in Large Apps
- Micro Frontends Tradeoffs
- Internationalization Architecture
- System Design Interview Framework