Every React codebase past a certain size contains a folder called components. And in most of them, that folder holds four different buttons, three modals with different APIs, and spacing values that were copied from whichever file was open at the time.
A design system is the fix, and most attempts at one fail. Not because the team lacks skill, but because they start in the wrong place: building a component library before building the foundations the components stand on.
We build design systems for agencies and product teams. This is the build order that produces systems teams actually use, rather than folders they route around.
What a Design System Is (And What It Is Not)
A design system is three layers: design tokens (the decisions), components (the implementations), and documentation with governance (the contract that keeps the first two in sync).
It is not a component library. A component library without tokens and governance is just a snapshot of one developer's preferences, and it drifts the day it ships. The drift is the disease. Everything in this guide is structured to prevent it. We wrote about the symptoms in Why Your Design System Is Failing Developers.
Step 1: Extract the Decisions Into Design Tokens
Tokens are named design decisions: colours, spacing, typography, radii, shadows, breakpoints, motion. They come first because every component will consume them, and retrofitting tokens into a built library means touching every component twice.
The practical format in 2026 is CSS custom properties, generated from a single source file, with TypeScript types alongside:
Define a small set of primitive scales: a colour palette, a spacing scale (4px base works for almost everything), a type scale, two or three radii. Then define semantic tokens on top: --color-surface, --color-text-muted, --space-inline-md. Components only ever reference semantic tokens.
The semantic layer is what makes theming, dark mode, and rebrands cheap. It is also the most commonly skipped step, and skipping it is why "change the brand colour" becomes a three-week project.
If the design lives in Figma, extract tokens from Figma variables rather than eyeballing values. The handoff mechanics matter, and we covered them in The Figma to Code Handoff.
Step 2: Build the Primitives (And Keep the List Short)
Primitives are the components everything else is made from. The starter set is smaller than teams expect:
Button, Input, Select, Checkbox and Radio, Text (typography wrapper), Stack and Grid (layout), Card, Modal, Toast, Tooltip, Badge. Eleven or twelve components cover the vast majority of product UI.
Three rules for building them:
Wrap, do not fork. For complex behavioural components (Modal, Select, Tooltip), build on a headless library like Radix or React Aria. Accessibility, focus management, and keyboard behaviour are solved problems. Your design system's value is the styling and the API, not re-deriving focus traps.
Design the API before the component. Props should express intent (variant="destructive", size="sm"), never raw styles (color="#E5484D"). The moment a component accepts arbitrary styling, the system has a hole, and every hole grows.
Compose, do not configure. A Card with twelve boolean props is a component nobody can predict. Card, Card.Header, Card.Body composition keeps each piece simple and lets product teams assemble what they need.
Step 3: TypeScript Is the Enforcement Layer
The design system's rules only hold if the compiler enforces them. Type every variant as a union ("primary" | "secondary" | "ghost"), export the token names as types, and make invalid combinations unrepresentable.
This is the difference between a design system as documentation (advisory, ignored under deadline) and a design system as infrastructure (the wrong thing does not compile). Strict types on a small API beat lint rules on a large one.
Step 4: Storybook as the Single Source of Truth
Every primitive gets a Storybook story showing every variant, every size, and every state, including the unglamorous ones: loading, disabled, error, empty, overflow.
Storybook earns its maintenance cost three ways: designers review real components instead of screenshots, new developers learn the API by browsing, and visual regression tools (Chromatic or equivalent) catch unintended changes in CI. A design system without visual regression testing relies on humans noticing pixel drift. Humans do not notice pixel drift.
Step 5: Patterns, Only After Primitives Are Stable
Patterns are assemblies: forms with validation, data tables, page shells, empty states. Teams that build patterns first bake product-specific assumptions into the foundation, and the system only fits the screen it was extracted from.
Sequence: primitives stabilise over two or three real features, then the recurring assemblies get promoted into patterns. Promotion is deliberate, with an API review, not a copy-paste into the shared folder.
This staged approach mirrors how we structure React codebases generally, covered in React Frontend Architecture That Scales.
Step 6: Governance, or the System Dies in Six Months
Every dead design system died the same way: a deadline arrived, someone built a one-off, the one-off multiplied, and within two quarters the system was one option among many.
The governance that prevents it is light but non-negotiable:
One named owner. Not a committee. One person who reviews component additions and API changes.
A contribution path. When a product team needs something the system lacks, there is a defined route: propose, review, add. If contributing is slower than forking, people fork.
An escape hatch with a tax. One-offs are allowed but live in a clearly marked unsafe or local namespace and are reviewed monthly for promotion or deletion. Pretending one-offs will not happen guarantees they happen invisibly.
Versioned releases. The system is a package with semver and a changelog, even inside a monorepo. Breaking changes are explicit, never silent.
The Build Timeline (Realistic Numbers)
For a team building alongside product work: tokens and tooling, one week. The twelve primitives with stories and tests, three to four weeks. First patterns, two weeks more, spread across real feature work. A usable v1 in roughly six weeks of focused effort.
The common failure is treating this as a side quest done in gaps. Half-built systems are worse than none, because they add a dependency without removing the inconsistency. Either resource it properly or buy it: an experienced external team can deliver the foundation in a fraction of the calendar time, with your team owning it from v1.
The Tooling Setup That Makes It Sustainable
The repository structure matters more than teams expect, because friction in consuming the system is the top reason product teams fork components instead of using them.
The setup that works for most teams: a monorepo with the design system as an internal package, consumed by the product apps through the workspace. Changes to a component and the feature using it land in one pull request, which keeps the system evolving with the product instead of lagging behind it. Separate repositories make sense only when multiple genuinely independent products consume the system, and even then, start in the monorepo and extract later.
The minimum toolchain: a build step that ships both ESM and type definitions, Storybook for the workbench, a visual regression service wired into CI, and changesets (or equivalent) for versioning and changelogs. Add a lint rule that forbids importing raw colour values and spacing literals in product code, so the token layer is enforced rather than encouraged.
One more piece that pays for itself: a single tokens.css (or generated equivalent) that marketing sites and non-React surfaces can consume. The design system's reach should not stop at the app boundary, because brand drift between the product and the marketing site is the first inconsistency users actually notice.
What to skip at this stage: component generators, custom CLI tooling, and elaborate documentation sites. A well-organised Storybook covers documentation until the team is large enough that someone owns developer experience full-time.
When Not to Build One
Under three developers, pre-product-market fit, or fewer than a dozen screens: use a styled component kit (shadcn/ui on Tailwind is the current sane default) and revisit in a year. A design system is leverage on consistency at scale. If there is no scale yet, the investment has nothing to multiply.
The right time is the moment two teams ship UI in parallel, or an agency starts its third project on the same visual foundation. That is when every week without a system starts compounding into rework.
The Measure of Success
Twelve months in, a healthy design system shows up in three numbers: the share of product UI built from system components (above 80 percent is strong), the time from "design approved" to "component in production" (days, not weeks), and the count of unreviewed one-off components in the codebase (trending down, not up). Track all three quarterly. A system that nobody measures becomes a system that nobody trusts, and a system nobody trusts is a folder of components waiting to be routed around. The build order in this guide gets you to v1. The measurement keeps v1 alive.
Related Reading
- Why Your Design System Is Failing Developers - the failure modes this build order is designed to avoid
- The Figma to Code Handoff - getting tokens and components out of Figma accurately
- Figma to Code Services - how we build production design systems from your design files