HomeJournalThis post

Why your design system isn't being used

A practical look at adoption, and why having a design system is rarely the real problem.

JP
JP Casabianca
Designer/Engineer · Bogotá

Most design-system adoption problems are diagnosed too late. By the time the team notices the system is not being used, the evidence is already scattered across feature branches: a local button variant, a copied card style, a one-off modal, a color token that exists only because a launch needed it by Friday.

That is why "we have a design system" is not a meaningful claim. A repository, a Figma library, and a Storybook are infrastructure. Adoption is behavior. The question is not whether the system exists. The question is whether the fastest path to shipping good product work goes through the system.

Product need System choice Screen shipped Contribution Healthy systems feed product work and learn from it.
Figure 1: Adoption is a loop. A system that only publishes components and never learns from product work becomes a catalog, not an operating model.

The symptom is drift, not disobedience

When teams bypass a system, it is tempting to call it a compliance problem. That framing usually makes things worse. Most designers and engineers are not trying to sabotage consistency. They are trying to ship a product surface under constraints the system did not anticipate.

The checkout needs a denser button group. The analytics page needs a compact empty state. The settings flow needs a destructive confirmation pattern. The design system has a modal, but not the variant with enough hierarchy for this moment. Someone solves the immediate problem locally, ships the feature, and promises to clean it up later.

That "later" is where systems go to die.

The better interpretation is that every local workaround is a signal. Some are noise, but many point to a missing primitive, unclear documentation, an over-specific component, or a contribution path that is too slow for the product team to trust.

Imports are a weak adoption metric

Counting component imports tells you whether the code touched the system. It does not tell you whether the system is helping.

A product can import the official Button and still override its spacing, color, radius, focus ring, and disabled state. A screen can use the official Card and still recreate the entire layout language in local CSS. Those are not adoption wins. They are evidence that the system is present but not sufficient.

Better adoption metrics are more uncomfortable:

  • How many one-off styles shipped in the last month?
  • How often do teams override system components?
  • How many new product surfaces can be built without adding a new token?
  • How many support questions repeat in Slack because documentation is incomplete?
  • How long does it take a product team to contribute a missing variant?

The useful number is not "system usage." The useful number is "avoidable local invention."

The adoption surface is mostly outside the component

The component itself is only one part of the adoption surface. The rest is examples, names, migration paths, contribution rules, and review habits.

If a designer cannot find the right component in Figma, they will draw a new one. If an engineer cannot tell whether a prop is meant for product teams or internal composition, they will use it incorrectly. If a PM cannot understand why a variant matters, they will treat the system as design preference instead of product infrastructure.

This is why design systems need operating documentation, not just reference documentation. Reference docs say what exists. Operating docs explain how to make decisions.

Good operating docs answer questions like:

  • Use this pattern when the user is choosing between peer options.
  • Do not use this pattern when the action is destructive.
  • If the screen needs a denser layout, start with this compact variant.
  • If you need a new variant, open an issue with a product example and proposed constraints.

Those details are not bureaucratic. They are the adoption layer.

Treat contribution as a product workflow

The biggest practical improvement is to make contribution feel normal. A system that cannot absorb product needs will be bypassed by product teams with deadlines.

I like a contribution model with three lanes:

  1. Local experiment: A feature team can try a new pattern inside the product when the system has no answer yet.
  2. Candidate pattern: If the pattern appears twice, it gets documented as a candidate with constraints and screenshots.
  3. System primitive: If the pattern proves durable, it becomes a named component, token, or guideline.

This keeps the system from becoming either too rigid or too chaotic. It also creates a path for work to move from product reality into shared language.

01Local experiment

Fast, scoped, tied to one product surface.

02Candidate pattern

Documented after repetition, still flexible.

03System primitive

Named, reviewed, implemented, supported.

Figure 2: Contribution should be staged. Not every idea deserves to become a component on day one.

Make the right thing faster

The best adoption strategy is not enforcement. It is speed.

If the system is easier to use than local invention, teams will use it. If it is slower, they will route around it. That means the boring details matter: package exports, Figma search, examples, prop names, responsive behavior, dark mode, accessibility states, and copy-paste snippets.

The system should answer common work with almost no ceremony. It should also make uncommon work feel possible without turning every exception into an argument.

The teams I have seen succeed usually do three things well:

  • They build system updates inside real product work.
  • They review product screens for system gaps, not only visual defects.
  • They maintain a short list of open system questions so drift becomes visible before it spreads.

What good looks like

A healthy design system feels almost invisible. New screens look coherent without designers policing every pixel. Engineers reach for primitives because they are reliable. Product managers trust that system work reduces risk instead of slowing delivery.

The system still changes. It still has gaps. But those gaps move through a visible contribution loop instead of becoming permanent local exceptions.

That is the difference between a library and an operating model. A library stores components. An operating model changes how a team ships.