Building a Design System That Doesn't Get Abandoned
designfrontendsystems

Building a Design System That Doesn't Get Abandoned

Most design systems die quietly — too rigid, too abstract, or too far from product reality. Here's what makes the difference between a system teams adopt and one they route around.

Arian ShahArian Shah
··3 min read

I've been part of three design system efforts. One died. One got forked by every team that used it. One actually worked. The difference wasn't the technology — it was how the system was built and, more importantly, for whom.

The graveyard is full of good intentions

The dead system was built correctly. Comprehensive Figma library. Storybook with every variant documented. Semantic tokens. Thorough accessibility testing.

Teams stopped using it six months in.

Why? It solved problems the team didn't have, and created friction around the problems they did. The button component had fourteen variants. Product needed two. To use the component library, you had to understand the token system, the variant API, the composition model. For a designer who just needed to ship a feature, the path of least resistance was to style a <div>.

Start with the product, not the system

The surviving system started differently: we took the five most-shipped UI patterns in the product and made those into components. Not a comprehensive component inventory — just the ones people were rebuilding from scratch every week.

First iteration:
- Button (2 variants: primary, ghost)
- Input (with label and error state)
- Modal
- Card
- Toast

Five components. That was it. No design tokens yet. The Tailwind config was the token system.

This gave us immediate leverage. Engineers stopped rebuilding these five things. Designers had a shared vocabulary for five patterns. The system earned trust before it tried to grow.

The component API is the product

Every component in your system has users: the engineers who import it. Their experience matters as much as the end user's.

A component with a bad API will be bypassed. This is what a bad API looks like:

// Too many props, unclear mental model
<Button
  variant="primary"
  size="md"
  leftIcon={<Icon />}
  rightIcon={<Icon />}
  isLoading={false}
  isDisabled={false}
  loadingText="Loading..."
  spinnerPlacement="start"
  onClick={handleClick}
>
  Submit
</Button>

And a better one:

// Composable, predictable, easy to read
<Button onClick={handleClick}>
  <Spinner /> {/* optional, rendered by consumer when needed */}
  Submit
</Button>

The composable version is more flexible and requires less documentation, because it uses React's existing composition model instead of reinventing it with props.

Versioning and the "one source of truth" lie

Here's the uncomfortable truth: there is no single source of truth in a design system. There's Figma, and there's code. They drift. Accepting this is the first step to managing it.

What works: a lightweight sync ritual. After every design system change:

  1. Update Figma
  2. Update code
  3. Post a changelog entry (even one sentence)
  4. Tag the release

The changelog is underrated. It's how teams find out the component they're using changed. It's how engineers and designers stay in sync without a meeting.

What "adoption" actually looks like

Successful adoption isn't teams using every component. It's teams using some components consistently, and knowing where to find answers when they hit an edge case.

The metric I care about: when an engineer needs a button, do they go to the design system first, or their last project? If it's the system, you're winning.


Design systems are fundamentally about reducing decision fatigue. Every time a team reaches for your component instead of writing their own, they've saved time, reduced inconsistency, and implicitly trusted the system. That trust is earned incrementally — by shipping components that work, APIs that make sense, and documentation that respects people's time.