I've built design systems from scratch, inherited legacy ones, and worked without them entirely. The difference in team velocity is stark—and it compounds over time.
The Hidden Cost of No System
Without a design system, every new feature involves invisible costs that accumulate:
Recreating Common Patterns
How many times has your team built a modal? A dropdown? A data table? Each implementation is slightly different, each takes time that could be spent on actual product work.
Inconsistent Implementations
Button A has 8px padding. Button B has 12px. The settings page uses one shade of gray; the dashboard uses another. Users notice this, even if subconsciously.
Designer-Developer Friction
Without shared vocabulary, designers and developers talk past each other. "Make it pop" means different things to different people. A design system creates a shared language.
Accessibility as an Afterthought
When every component is custom, accessibility gets forgotten. A design system bakes accessibility in once and applies it everywhere.
What a Good Design System Includes
1. Design Tokens
Start with the atoms: colors, typography, spacing scales. These should be tokens, not hardcoded values.
// tokens.ts
export const colors = {
primary: {
50: '#eff6ff',
500: '#3b82f6',
900: '#1e3a8a',
},
// ...
};
export const spacing = {
xs: '0.25rem',
sm: '0.5rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
};
Tokens create a single source of truth. Change once, update everywhere.
2. Primitive Components
Build the foundational elements: Button, Input, Text, Box. These encode your design decisions.
A Button component isn't just styled—it handles loading states, disabled states, variants, sizes, and accessibility:
<Button
variant="primary"
size="md"
loading={isSubmitting}
disabled={!isValid}
>
Submit
</Button>
3. Composite Components
Combine primitives into common patterns: Card, Modal, Dropdown, DataTable. These solve specific UI problems with consistent behavior.
4. Patterns and Guidelines
Document how components combine. A form pattern. A data table pattern. A modal flow pattern. This is where designer intent gets preserved and developer questions get answered.
5. Documentation
Every component needs:
- Usage examples
- Props documentation
- Do's and don'ts
- Accessibility notes
- Edge cases
Building Your First Design System
You don't need a full system on day one. Here's how I approach it:
Week 1: Foundation
- Define your color palette with semantic naming (primary, secondary, error, success)
- Establish a typography scale (heading sizes, body text, captions)
- Create a spacing scale (4px, 8px, 16px, 24px, 32px...)
- Document these in code and Figma
Week 2-3: Core Components
Build 5-10 components that you use constantly:
- Button (variants, sizes, states)
- Input (text, number, with validation)
- Text (typography component)
- Box (layout primitive)
- Card (content container)
Week 4+: Grow Organically
As you build features, identify repeated patterns. Before implementing, ask: should this be a component?
Not everything should be. Abstract when you've built the same thing three times, not preemptively.
Technical Decisions
Styling Approach
I've had success with:
- Tailwind CSS: For utility-first, fast iteration
- CSS-in-JS: For dynamic styling and co-location
- CSS Modules: For scoped styles without runtime cost
Pick based on your team's experience and project needs.
Component API Design
Follow these principles:
- Composition over configuration: Prefer
<Card><CardHeader/><CardBody/></Card>over<Card header={} body={}/> - Sensible defaults: Components should work out of the box
- Escape hatches: Allow className or style overrides for edge cases
- Accessibility built-in: ARIA labels, keyboard navigation, focus management
Versioning and Distribution
For larger teams:
- Separate package for the design system
- Semantic versioning
- Changelog for every release
- Migration guides for breaking changes
Common Mistakes
1. Over-Abstracting Early
Don't build a component until you need it in three places. Premature abstraction creates unused code and maintenance burden.
2. Ignoring Developer Experience
If the design system is harder to use than raw HTML, developers won't use it. APIs should be intuitive, documentation should be excellent.
3. No Governance
Someone needs to own the system. Without clear ownership, it fragments—different teams add conflicting components, patterns diverge.
4. Designing in Isolation
A design system should serve real product needs. Build components as you need them, not in a vacuum.
The Payoff
Teams with mature design systems:
- Ship faster: No reinventing the wheel
- Maintain consistency: Users get a cohesive experience
- Onboard quickly: New developers are productive faster
- Iterate confidently: Change a component, update everywhere
I've seen teams double their velocity after investing in a design system. The ROI is real, but it requires sustained investment.
Getting Buy-In
If you're struggling to convince stakeholders:
- Track time spent on "custom" UI work
- Document inconsistencies across the product
- Show competitor products with stronger design systems
- Start small, prove value, then expand
Design systems are infrastructure. Like good infrastructure, they're invisible when they work—and painfully obvious when they don't.
Build yours before the pain becomes unbearable.

