Designing a Design System in React: Tokens, Components, and What Actually Scales

Design systems usually fail not because teams picked the wrong component library.
They fail because they treat a design system like a component dump instead of a product with contracts.
A system that scales has to do three jobs at once:
- Give designers and engineers a shared language.
- Make common UI work faster than custom UI.
- Constrain inconsistency without blocking delivery.
What a Design System Actually Is
A real design system is not just a Figma file or a component package.
It is the combination of foundations (tokens), primitives, composed components, usage guidance, and governance.
If you only ship components without these contracts, you still get visual drift and API chaos.
Start with Token Strategy, Not Component Names
Teams often start with “we need a Button component.” A stronger starting point is token decisions:
- semantic color roles,
- spacing scale,
- typography scale,
- radii and elevation,
- motion timing and easing.
Raw vs semantic tokens
Use both layers:
- Raw tokens: actual values (
#0ea5e9,8px,16px). - Semantic tokens: intent (
color.text.primary,space.md,surface.card).
export const raw = {
blue500: '#0ea5e9',
slate900: '#0f172a',
white: '#ffffff',
space2: '8px',
space4: '16px',
radiusSm: '6px',
};
export const semantic = {
color: {
textPrimary: raw.slate900,
textInverse: raw.white,
actionPrimaryBg: raw.blue500,
},
space: {
sm: raw.space2,
md: raw.space4,
},
radius: {
control: raw.radiusSm,
},
};
Semantic mapping lets you change themes without rewriting component logic.
Primitives Before Complex Components
A scalable React system typically layers this way:
- Foundation: tokens and theme contracts.
- Primitives:
Box,Text,Stack,Inline,Icon. - Patterns: reusable combinations.
- Product components: domain-level components near feature teams.
If you skip primitives, every component reimplements spacing and layout rules.
API Design: Composition Over Configuration
Over-configured components look flexible but become hard to maintain.
Prefer composable APIs:
<Card>
<Card.Header>
<Card.Title>Revenue</Card.Title>
</Card.Header>
<Card.Body>
<RevenueChart />
</Card.Body>
<Card.Footer>
Updated 5m ago
</Card.Footer>
</Card>
Practical API rules:
- keep props focused,
- use explicit subcomponents for structure,
- reserve variants for true visual/state differences,
- avoid booleans that overlap in meaning.
TypeScript Contracts That Age Well
Design systems are shared infrastructure, so contracts matter.
type SpaceToken = 'sm' | 'md' | 'lg';
interface StackProps {
gap?: SpaceToken;
align?: 'start' | 'center' | 'end' | 'stretch';
}
Use narrow public APIs and clear versioning intent:
- visual-only non-breaking,
- behavior change with migration note,
- hard breaking change needing major release.
Accessibility Has to Be Built In
For each component define baseline guarantees:
- keyboard behavior,
- focus visibility,
- ARIA expectations,
- contrast expectations,
- screen-reader naming.
If these are optional, they get skipped under delivery pressure.
Build the Surface Area That Pays Back
Don’t systemize everything at once. High-leverage rollout order:
- Typography and spacing primitives.
- Button/Input/Select/Checkbox.
- Form layout patterns.
- Modal/Toast/Dropdown/Tabs.
- Table and data-display primitives.
Governance: The Difference Between Growth and Drift
Without governance, design systems fork silently.
Use a lightweight model:
- system owners,
- contributor path for feature teams,
- RFC process for foundational additions,
- definition of done with docs, tests, accessibility checks, and migration notes.
Adoption Strategy for Existing Products
Use strangler migration, not a big-bang rewrite:
- use system components for all new screens,
- replace legacy components during normal feature work,
- track migration progress by domain.
Support adoption with lint rules, codemods, and practical Storybook examples.
Performance and Bundle Discipline
Protect against hidden bundle tax:
- tree-shakable exports,
- avoid side-effectful barrels,
- monitor package size in CI,
- test heavy components with realistic data.
Documentation Engineers Actually Use
Each component page should answer:
- when to use it,
- when not to,
- minimal and advanced examples,
- accessibility notes,
- migration notes.
A useful doc page usually beats adding another variant.
How to Measure if the System Is Working
Track outcomes, not component count:
- time-to-ship for common UI tasks,
- percentage of screens using system components,
- duplicated pattern reduction,
- accessibility regressions in shared components,
- one-off components added per sprint.
Final Takeaway
A React design system scales when it behaves like a product platform:
- semantic token contracts first,
- composable APIs,
- explicit accessibility guarantees,
- governance with ownership,
- incremental migration under real delivery pressure.
When those are in place, the system becomes a velocity multiplier instead of maintenance overhead.