Every product team eventually builds a design system. Most of them quietly die within a year — designers stop updating it, engineers stop trusting it, and PMs never knew it existed. Here is why it happens and what to do instead.
Why design systems fail
- They are built upfront, before real product needs show up. Teams catalog 40 components before shipping one that anyone uses.
- They are maintained by nobody. Ownership is diffuse, updates lag product, and drift starts immediately.
- They do not match the code. Figma says one thing, Storybook says another, production says a third.
- They are too rigid. If every new design needs a new component, contributors stop proposing them.
What works instead
Start with tokens, not components. Extract components from real product screens, not from a library wish list.
1. Tokens first
Colors, spacing, typography, radii, shadows. Keep them in a single source of truth — Figma Variables mirrored to tokens.json — and generate both the Figma library and the code constants from it.
2. Extract, do not invent
Do not design a component until three product screens need it. When they do, formalize the existing pattern — do not invent a new one.
3. Name an owner
One designer and one engineer, with a small percentage of their time allocated. Not a committee. They are the final call on whether a component is "in the system."
4. Ship the docs alongside the code
Storybook for live demos, with usage guidance and do's and don'ts inline. If someone has to visit three places to learn a component, they will not use it correctly.
Governance without bureaucracy
Contributions are proposed via a simple template: what pattern, what products need it, what existing components it replaces. Review takes hours, not weeks. Anything else kills contribution.
Measuring adoption
Track component usage across your codebase with a simple script. If adoption is below 50% a quarter after release, something is off — usually the component does not match real design needs, and it needs a rework, not more evangelism.
Anatomy of the token layer
The biggest leverage point in any design system is the token layer, because everything visible inherits from it. We structure tokens in three tiers so a single change can ripple predictably across an entire product surface:
- Primitive tokens — raw values with no meaning attached:
blue-500: #2563eb,space-4: 16px,font-size-3: 1.125rem. These almost never change. - Semantic tokens — intent-based aliases that reference primitives:
color-action-primary,color-surface-raised,space-inset-md. Components only ever consume this tier. - Component tokens — the narrowest scope, like
button-padding-xorcard-radius, which point at semantic tokens for the rare cases that need a local override.
This indirection is what makes dark mode, white-labelling, and rebrands tractable. When a fintech client asked us to ship a second brand theme, we swapped the semantic-to-primitive mapping and shipped both themes in a sprint — no component was touched. If you want a partner to set this foundation up correctly, that is exactly the kind of work our UI/UX design team scopes on day one.
Components people actually reuse
A component earns its place in the system when it is accessible, themeable, and boring to use. We hold every shared component to a short, non-negotiable checklist before it ships:
- States are complete — default, hover, focus, active, disabled, loading, and error are all designed and built, not bolted on later.
- Accessibility is baked in — keyboard navigation works, focus rings are visible, color contrast meets WCAG 2.2 AA, and interactive elements expose correct ARIA roles and labels. Accessibility is cheapest at the component level and brutally expensive to retrofit at the screen level.
- The API is small — a handful of well-named props beat twenty boolean flags. If a component needs a configuration manual, it is two components wearing a trench coat.
- It is responsive by default — behavior at mobile, tablet, and desktop breakpoints is specified, not improvised in product code.
The best component is the one nobody has to think about. Predictability is a feature, and surprise is a bug.
Keeping Figma and code in sync
Drift between design and code is the silent killer of trust. Once an engineer finds one component where Figma lies, they stop trusting all of them and start reinventing. We keep the two honest with a few practices:
- Generate tokens from one source so Figma Variables and code constants can never disagree by accident.
- Mirror the component inventory: every Figma component maps one-to-one to a coded component with the same name. No orphans on either side.
- Run visual regression snapshots in CI so an unintended pixel change fails the build instead of shipping silently.
- Review design and code changes together in the same pull request whenever a component changes.
This is also where AI is starting to pull real weight: we use tooling to flag stray hard-coded hex values, suggest the nearest semantic token, and auto-draft component documentation from prop types. If you are curious how we fold those workflows into delivery, our AI & machine learning practice has the details.
Documentation that gets read
Documentation fails when it is a separate chore. We co-locate it with the component so it updates in the same commit. A good component page answers four questions in under a minute: what is it, when do I use it, when do I not use it, and how do I drop it in. Live examples beat screenshots, do's-and-don'ts pairs beat paragraphs, and a copyable code snippet at the top beats everything.
Governance without bureaucracy
Contributions are proposed via a simple template: what pattern, what products need it, what existing components it replaces. Review takes hours, not weeks. Anything else kills contribution. We version the system with semantic versioning, ship a short changelog with every release, and reserve major versions for breaking changes so teams can upgrade on their own schedule.
Measuring adoption
Track component usage across your codebase with a simple script. If adoption is below 50% a quarter after release, something is off — usually the component does not match real design needs, and it needs a rework, not more evangelism. A few metrics worth watching over time:
- Coverage — the share of UI built from system components versus one-off markup.
- Token compliance — how often raw values appear in code instead of tokens.
- Time-to-first-screen — how quickly a new feature can be assembled from existing parts.
The uncomfortable truth
A design system is a product. It has users (designers and engineers), requirements, and a backlog. Teams that treat it like documentation end up with documentation nobody reads. Teams that treat it like a product — with PMs, feedback loops, and versioned releases — end up with adoption. If you would rather not learn that the expensive way, talk to us — we have rolled out systems that survived rebrands, team turnover, and three years of feature pressure.
Frequently Asked Questions
What is the difference between a design system and a UI kit?
A UI kit is a static collection of styles and components, usually living only in a design tool. A design system is broader: it pairs those components with design tokens, coded implementations, documentation, accessibility rules, contribution governance, and versioned releases. The kit is the visible surface; the system is the product behind it that keeps designers, engineers, and PMs aligned over time.
Should we start with components or with design tokens?
Start with tokens. Colors, spacing, typography, radii, and shadows are the foundation every component inherits from, so getting them into a single source of truth first means later changes — dark mode, rebrands, white-labelling — ripple predictably instead of requiring manual edits everywhere. Build components only after three real product screens prove the pattern is needed, and formalize the existing pattern rather than inventing a new one.
How do we keep Figma and code from drifting apart?
Generate tokens from one shared source so Figma Variables and code constants can never disagree by accident, and mirror the component inventory one-to-one so every Figma component maps to a coded component with the same name. Add visual regression snapshots in CI so unintended pixel changes fail the build, and review design and code changes together in the same pull request whenever a component changes.
How do we measure whether a design system is working?
Track component usage across your codebase with a simple script and watch a few metrics over time: coverage, the share of UI built from system components versus one-off markup; token compliance, how often raw values appear instead of tokens; and time-to-first-screen, how quickly a new feature can be assembled from existing parts. If adoption is below 50% a quarter after release, the component usually does not match real design needs and should be reworked rather than re-evangelized.
← Back to blog