Building a Design System for React Applications
Design systems ensure consistency across applications. After building production design systems, here’s how to create one effectively.
What is a Design System?
A design system includes:
- Components - Reusable UI elements
- Tokens - Design values (colors, spacing)
- Documentation - Usage guidelines
- Tools - Development utilities
Project Structure
design-system/
├── src/
│ ├── components/
│ ├── tokens/
│ ├── utils/
│ └── index.ts
├── stories/
├── docs/
└── package.json
Design Tokens
Colors
// tokens/colors.ts
export const colors = {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
500: '#0ea5e9',
900: '#0c4a6e',
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
500: '#6b7280',
900: '#111827',
},
};
export type ColorScale = typeof colors.primary;
Spacing
// tokens/spacing.ts
export const spacing = {
xs: '0.25rem', // 4px
sm: '0.5rem', // 8px
md: '1rem', // 16px
lg: '1.5rem', // 24px
xl: '2rem', // 32px
};
export type Spacing = keyof typeof spacing;
Typography
// tokens/typography.ts
export const typography = {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['Fira Code', 'monospace'],
},
fontSize: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
},
fontWeight: {
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
},
};
Components
Button Component
// components/Button.tsx
import React from 'react';
import { colors, spacing } from '../tokens';
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
onClick?: () => void;
disabled?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
children,
onClick,
disabled = false,
}) => {
const baseStyles = {
padding: spacing.md,
borderRadius: '0.375rem',
border: 'none',
cursor: disabled ? 'not-allowed' : 'pointer',
opacity: disabled ? 0.5 : 1,
};
const variantStyles = {
primary: {
backgroundColor: colors.primary[500],
color: 'white',
},
secondary: {
backgroundColor: colors.gray[500],
color: 'white',
},
outline: {
backgroundColor: 'transparent',
border: `1px solid ${colors.primary[500]}`,
color: colors.primary[500],
},
};
const sizeStyles = {
sm: { padding: spacing.sm, fontSize: '0.875rem' },
md: { padding: spacing.md, fontSize: '1rem' },
lg: { padding: spacing.lg, fontSize: '1.125rem' },
};
return (
<button
style=
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
};
Input Component
// components/Input.tsx
import React from 'react';
import { colors, spacing } from '../tokens';
interface InputProps {
type?: 'text' | 'email' | 'password';
placeholder?: string;
value: string;
onChange: (value: string) => void;
error?: string;
}
export const Input: React.FC<InputProps> = ({
type = 'text',
placeholder,
value,
onChange,
error,
}) => {
return (
<div>
<input
type={type}
placeholder={placeholder}
value={value}
onChange={(e) => onChange(e.target.value)}
style=
/>
{error && (
<div style=>
{error}
</div>
)}
</div>
);
};
Storybook
Setup
npx sb init
Story Example
// Button.stories.tsx
import { Button } from './Button';
export default {
title: 'Components/Button',
component: Button,
};
export const Primary = {
args: {
variant: 'primary',
children: 'Click me',
},
};
export const Secondary = {
args: {
variant: 'secondary',
children: 'Click me',
},
};
export const Outline = {
args: {
variant: 'outline',
children: 'Click me',
},
};
Documentation
Component Documentation
# Button Component
## Usage
\`\`\`tsx
import { Button } from '@design-system/components';
<Button variant="primary" onClick={handleClick}>
Click me
</Button>
\`\`\`
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | 'primary' \| 'secondary' \| 'outline' | 'primary' | Button style |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Button size |
| disabled | boolean | false | Disable button |
Best Practices
- Consistent naming - Clear component names
- TypeScript - Type safety
- Documentation - Usage examples
- Accessibility - ARIA attributes
- Testing - Component tests
- Versioning - Semantic versioning
- Changelog - Track changes
- Examples - Storybook stories
Conclusion
Design systems provide:
- Consistency
- Reusability
- Maintainability
- Developer experience
Start with tokens, then build components. The patterns shown here create production-ready design systems.
Building design systems for React from October 2020, covering components, tokens, and documentation.