Front-end Engineering Lab
PatternsDesign Systems

Design Systems

Build scalable, maintainable design systems like Shopify and Atlassian

Design Systems

Design systems are the foundation of consistent, scalable UIs. Companies like Shopify, Atlassian, and GitHub use sophisticated design systems to maintain quality across hundreds of products and thousands of components.

What is a Design System?

A design system is more than a component library—it's a complete set of standards, documentation, and principles that guide product design and development.

Components of a Design System:

  • Design Tokens: Colors, spacing, typography values
  • Component Library: Reusable UI components
  • Documentation: Usage guidelines, do's and don'ts
  • Patterns: Common UI patterns and solutions
  • Principles: Design philosophy and values

Why Design Systems Matter

Benefits:

  • Consistency: Same look and feel everywhere
  • Speed: Build faster with reusable components
  • Quality: Battle-tested, accessible components
  • Scalability: Maintain quality as team grows
  • Collaboration: Common language for designers and developers

Problems They Solve:

  • Inconsistent UI across products
  • Duplicate components with different APIs
  • Slow feature development
  • Accessibility issues
  • Difficult to implement design changes

Anatomy of a Design System

Design System
├── Design Tokens
│   ├── Colors (primitives + semantic)
│   ├── Typography (font families, sizes, weights)
│   ├── Spacing (margins, paddings, gaps)
│   ├── Shadows (elevation system)
│   ├── Borders (radius, widths)
│   └── Breakpoints (responsive system)

├── Components
│   ├── Primitives (Button, Input, Text)
│   ├── Layout (Stack, Grid, Flex)
│   ├── Feedback (Alert, Toast, Modal)
│   ├── Navigation (Nav, Tabs, Breadcrumbs)
│   └── Complex (DataTable, Calendar, Editor)

├── Patterns
│   ├── Forms (validation, layout)
│   ├── Navigation (menus, sidebars)
│   ├── Data Display (tables, lists, cards)
│   └── Feedback (loading, errors, empty states)

└── Documentation
    ├── Getting Started
    ├── Design Principles
    ├── Component Docs (props, examples, accessibility)
    └── Contribution Guidelines

Design Tokens Architecture

Design tokens are the atomic building blocks:

// ❌ BAD: Hardcoded values
<button style={{ 
  color: '#0066CC',
  padding: '12px 24px',
  borderRadius: '6px',
  fontSize: '14px'
}}>
  Click me
</button>

// ✅ GOOD: Design tokens
<button style={{ 
  color: tokens.color.primary,
  padding: `${tokens.spacing[3]} ${tokens.spacing[6]}`,
  borderRadius: tokens.borderRadius.md,
  fontSize: tokens.fontSize.sm
}}>
  Click me
</button>

Token Hierarchy

Primitive Tokens (Raw Values)

// tokens/primitives.ts
export const primitives = {
  color: {
    blue: {
      50: '#EFF6FF',
      100: '#DBEAFE',
      200: '#BFDBFE',
      500: '#3B82F6',
      700: '#1D4ED8',
      900: '#1E3A8A',
    },
    gray: {
      50: '#F9FAFB',
      100: '#F3F4F6',
      500: '#6B7280',
      900: '#111827',
    },
  },
  spacing: {
    0: '0',
    1: '0.25rem',  // 4px
    2: '0.5rem',   // 8px
    3: '0.75rem',  // 12px
    4: '1rem',     // 16px
    6: '1.5rem',   // 24px
    8: '2rem',     // 32px
  },
};

Semantic Tokens (Meaning)

// tokens/semantic.ts
export const semantic = {
  color: {
    primary: primitives.color.blue[500],
    secondary: primitives.color.gray[500],
    
    background: {
      default: '#FFFFFF',
      subtle: primitives.color.gray[50],
    },
    
    text: {
      default: primitives.color.gray[900],
      muted: primitives.color.gray[500],
    },
    
    border: {
      default: primitives.color.gray[200],
      hover: primitives.color.gray[300],
    },
    
    feedback: {
      success: '#10B981',
      warning: '#F59E0B',
      error: '#EF4444',
      info: primitives.color.blue[500],
    },
  },
  
  spacing: {
    xs: primitives.spacing[1],
    sm: primitives.spacing[2],
    md: primitives.spacing[4],
    lg: primitives.spacing[6],
    xl: primitives.spacing[8],
  },
};

Component API Design Principles

1. Consistent Naming

// ✅ GOOD: Consistent prop names
<Button variant="primary" size="md" disabled />
<Input variant="outline" size="md" disabled />
<Select variant="filled" size="md" disabled />

// ❌ BAD: Inconsistent naming
<Button type="primary" btnSize="medium" isDisabled />
<Input style="outline" inputSize="md" readonly />
<Select appearance="filled" selectSize="m" inactive />

2. Composition Over Configuration

// ✅ GOOD: Composable
<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>
    Content here
  </CardContent>
  <CardFooter>
    <Button>Action</Button>
  </CardFooter>
</Card>

// ❌ BAD: Props explosion
<Card
  title="Title"
  content="Content here"
  footerActions={[{ label: 'Action', onClick: fn }]}
  showHeader
  showFooter
/>

3. Sensible Defaults

// Button with smart defaults
<Button>Submit</Button>
// Defaults to: variant="primary", size="md", type="button"

<Button variant="ghost">Cancel</Button>
// Only override what's needed

Design System Layers

Layer 1: Tokens

// Immutable values
export const tokens = {
  color: { ... },
  spacing: { ... },
  typography: { ... },
};

Layer 2: Primitives

// Basic building blocks
import { Button, Input, Text, Box } from '@/components/primitives';

Layer 3: Patterns

// Common compositions
import { Form, FormField, FormError } from '@/components/patterns';

Layer 4: Features

// Domain-specific components
import { ProductCard, CheckoutForm } from '@/features';

Theming Architecture

// Multi-theme support
const themes = {
  light: {
    background: '#FFFFFF',
    text: '#000000',
    primary: '#0066CC',
  },
  dark: {
    background: '#000000',
    text: '#FFFFFF',
    primary: '#3B82F6',
  },
  brand: {
    background: '#F5F5F5',
    text: '#1A1A1A',
    primary: '#FF6B00',
  },
};

// Theme provider
<ThemeProvider theme={themes.light}>
  <App />
</ThemeProvider>

Real-World Examples

Shopify Polaris

  • 50+ components
  • Comprehensive documentation
  • Built-in accessibility
  • Mobile-first design

Atlassian Design System

  • Token-based architecture
  • Dark mode support
  • Cross-platform (web, mobile, desktop)
  • Extensive patterns library

GitHub Primer

  • React components
  • ViewComponent (Rails)
  • Figma library
  • Open source

Building Your Design System

1. Start Small

Phase 1: Foundation
- Design tokens
- Basic primitives (Button, Input, Text)
- Typography system
- Color palette

Phase 2: Components
- Common components (10-15)
- Documentation
- Storybook

Phase 3: Patterns
- Form patterns
- Navigation patterns
- Data display

Phase 4: Scale
- Advanced components
- Animation system
- Contribution guidelines

2. Token-First Approach

Start with design tokens, then build components using them.

3. Documentation-Driven

Document before building—clarify API design first.

4. Accessibility Built-In

Every component should be accessible by default.

5. Version and Maintain

Treat your design system as a product—version it, maintain it, improve it.

Best Practices

  1. Token-Based: Everything references tokens
  2. Type-Safe: TypeScript for all components
  3. Accessible: WCAG AA minimum
  4. Documented: Clear examples and guidelines
  5. Testable: Unit + visual regression tests
  6. Versioned: Semantic versioning
  7. Composable: Small, reusable pieces
  8. Themeable: Support multiple themes
  9. Responsive: Mobile-first design
  10. Maintainable: Clear ownership and processes

Common Pitfalls

Too many variants: 20 button variants
3-5 core variants, compose for variations

Prop overload: 50 props per component
Composition and sensible defaults

Inconsistent naming: Different conventions
Establish naming guidelines

No versioning: Breaking changes everywhere
Semantic versioning with changelogs

Poor documentation: "Just read the code"
Examples, guidelines, accessibility notes

Tools and Libraries

Component Development:

  • Storybook: Component explorer
  • Chromatic: Visual testing
  • Radix UI: Unstyled, accessible primitives
  • Headless UI: Tailwind's component library

Token Management:

  • Style Dictionary: Token transforms
  • Theo: Salesforce's token tool
  • Figma Tokens: Design-to-code sync

Documentation:

  • Docusaurus: Documentation sites
  • Fumadocs: Next.js docs (what you're reading!)
  • VuePress: Vue-based docs

Measuring Success

Key Metrics:

  • Component reuse rate
  • Time to build new features
  • Design consistency score
  • Developer satisfaction
  • Accessibility compliance

Next Steps

Explore specific design system topics:

A great design system is the foundation of a great product—invest in it early and maintain it well.

On this page