Design Systems
A design system is not a component library. The library is the deliverable people notice; the system is the library plus the tokens it's built from, the documentation that explains when to use each part, the contribution process, the release discipline, and the social agreement that this is how the organization builds interfaces.
That distinction explains the field's most common failure. Teams build a beautiful set of components, publish it, and discover a year later that product teams are still writing one-off buttons — because the system's components didn't fit their cases, the documentation didn't answer their questions, and nobody had authority or incentive to close the gap. Design systems fail on adoption far more often than on craft.
The successful ones tend to start small, grow from demonstrated demand rather than speculation, and treat the product teams as customers rather than as an audience.
TL;DR
- A design system = components + tokens + documentation + governance. Missing any one of them produces a library nobody uses.
- Build from demonstrated need. Five components everyone actually repeats beat sixty nobody asked for.
- Don't start from zero — layer your tokens and brand on Radix, shadcn/ui, Base UI, or Material.
- Design component APIs for composition, not for configuration. A
variantprop with fifteen values is a design smell. - Accessibility belongs in the system — solve keyboard, focus, and ARIA once and every consumer inherits it.
- Version with semver and treat visual changes as breaking when they are.
- Measure adoption, not component count. Coverage and one-off overrides are the honest metrics.
- Documentation is the product surface. An undocumented component effectively doesn't exist.
Quick Example
A component designed for composition rather than configuration:
The composition version absorbs requirements the author never anticipated, which is precisely what determines whether a system survives contact with real products.
Core Concepts
The layers
Each layer is derived from the one below. When a product team needs a value that isn't in the token set, that's a signal about the token set — not a reason to hardcode a hex value.
What belongs in the system
The test is repetition: something built for the third time in three different products belongs in the system. Something speculative does not — a component built for an imagined future consumer usually has the wrong API when a real one appears.
Build vs. adopt
Level 2 or 3 is right for most organizations. Headless libraries have already solved keyboard navigation, focus management, screen reader semantics, and the genuinely hard parts of a combobox or a modal — problems that take months to get right and are invisible until they're wrong. Building those yourself is rarely the differentiating work.
Level 4 is correct when speed matters more than visual distinctiveness, such as internal tools. Level 1 is correct when you have a dedicated systems team and a strong brand requirement.
Documentation
Documentation is not a byproduct of the system; it's the interface to it. Each component needs:
- What it's for, and — equally important — when to use a different one.
- Live, interactive examples you can copy.
- A props table, generated from types rather than hand-written.
- Do and don't examples, with the reasoning stated.
- Accessibility notes: keyboard behavior, required labels, focus handling.
Tools: Storybook for component development and interaction testing, Docusaurus or a custom site for narrative guidance, and type-generated prop tables so the documentation can't drift from the code. See Docs-as-Code.
Versioning and release
Visual changes deserve care: a button whose padding changes by 4px breaks layouts downstream even though nothing in the API changed. Treat significant visual changes as breaking, ship a codemod with any rename, and support the previous major for a stated period.
A changeset-driven release (Changesets, semantic-release) with an automatically generated changelog removes the friction that otherwise makes teams batch up risky releases.
Governance
Federated is the common landing point, and it needs an explicit contribution process: how to propose a component, what "done" means (tests, docs, a11y review, tokens only), who reviews, and how long it takes. Without that, contributors are blocked and go build their own thing — which is exactly the outcome the system exists to prevent.
Adoption
This is the part that decides whether the investment pays off, and it's mostly not a technical problem.
Measure the right things
Instrumenting this is feasible: lint rules that flag raw hex colors and non-token spacing, a codebase scan for local component definitions that shadow system ones, and analytics on the documentation site.
Make the system the easiest path
Adoption follows convenience far more reliably than it follows mandates. That means: excellent documentation with copyable examples, a CLI or template that scaffolds correctly by default, codemods for migrations, fast responses to contribution requests, and — critically — components that actually cover the real cases rather than the idealized ones.
Fix the escape hatches
When a team writes a one-off component, that's information. Either the system component was missing a capability, the documentation didn't surface it, or the API made the case awkward. Treat each one as a bug report about the system rather than as non-compliance.
Best Practices
Start with what's already repeated
Audit the existing products for duplicated components. The five most-duplicated ones are your first release, and they arrive with proven demand and known requirements — a far better starting point than a component inventory drawn from a design file.
Build on a headless foundation
Radix, Ark UI, or React Aria give you correct keyboard interaction, focus trapping, and ARIA semantics. These are hard, boring, and heavily tested upstream. Spend your effort on the token system and the API design, which is where your organization's needs are actually specific.
Design APIs for composition
Compound components (Card.Header) and slot props absorb requirements you can't anticipate. A component with more than about eight props is usually one that should have been decomposed.
Ship accessibility as a system property
Contrast ratios come from the color system. Focus visibility comes from the token set. Keyboard behavior and ARIA come from the components. Solved once, every consumer inherits it; solved per feature, it's relitigated forever and inconsistently. See Accessibility.
Allow controlled escape hatches
A className passthrough and an asChild pattern let teams handle the 5% of cases the system doesn't cover, without forking. A system with no escape hatch gets abandoned at the first hard case; one with an unbounded style prop stops being a system.
Version and communicate changes properly
Semver, generated changelogs, codemods for renames, and a deprecation period. Teams that have been burned by a surprise breaking change pin the version and stop upgrading, which is how a system quietly dies.
Treat product teams as customers
Office hours, a responsive support channel, and short turnaround on contributions. The systems that get adopted are the ones where asking for something works. This is a service relationship, not a compliance one.
Test visually
Storybook plus visual regression (Chromatic, Playwright screenshots) catches the changes unit tests can't see — a padding shift, a broken dark variant, a focus ring that disappeared. For a shared library, visual regressions are the expensive kind of bug because they land everywhere at once.
Common Mistakes
Building the whole library before anyone uses it
Configuration props instead of composition
Hardcoding values inside components
No escape hatch
Measuring component count as success
Treating accessibility as a component-by-component task
FAQ
When is a design system worth building?
When the cost of inconsistency exceeds the cost of coordination — usually multiple products or teams, or one product with enough surface that the same component is being rebuilt. Below that, adopt an existing library and layer your tokens on it. A two-person team building a design system is usually avoiding the product.
Should we build from scratch or adopt something?
Adopt, then customize. Headless libraries (Radix, React Aria) have solved the accessibility and interaction problems that take the longest and are hardest to verify. shadcn/ui's copy-in model is popular precisely because you own the resulting code while starting from something correct. Build from scratch only with a dedicated team and requirements nothing else meets.
Who should own it?
A small dedicated core team (often 2–5 people spanning design and engineering) that owns standards, tokens, infrastructure, and review — with product teams contributing components under that review. Pure central ownership becomes a bottleneck; pure federation produces inconsistency. The core team's most important output is often unblocking contributors rather than writing components.
How do we handle multiple brands or themes?
Through the token layer. Semantic tokens (color-action-primary) reference primitive tokens (blue-600), and a brand swaps the primitive mapping while every component stays unchanged. Components must never reference primitives directly — that single rule is what makes multi-brand possible. See Design Tokens and Dark Mode & Theming.
How do we keep design and code in sync?
Generate both from the same token source — Figma variables and CSS custom properties from one pipeline (Style Dictionary, Tokens Studio). For components, accept that a Figma component and a React component are two implementations of one contract and require review on both sides for changes. Perfect automatic sync is a persistent aspiration; a shared token pipeline plus a shared review process is what actually works.
How do we get teams to actually use it?
Make it the easiest path, respond fast to gaps, and demonstrate value on a real product first. Mandates without quality produce compliance theater — teams wrapping system components in their own layer. The strongest adoption lever is a flagship product visibly built on the system, shipping faster because of it.
Related Topics
- Design Tokens — The layer everything else derives from
- Figma for Developers — Reading the design source accurately
- Dark Mode & Theming — Multi-theme architecture
- Color Systems for UI — Building an accessible palette
- Web Typography — The type scale in the system
- UI Animation — Motion tokens and shared transitions
- Accessibility — Solved at the system layer
- Storybook — Component development and documentation
- Monorepos — Where a system and its consumers often live
- Technical Writing — Documenting a system so it gets used
- Design & UX Engineering — The full hub