A design system is not a component library. It is an agreement about how decisions get made, written down in code so nobody has to renegotiate it every sprint. When I join a product team, the interface is rarely the problem — the missing agreement is.
Start with tokens, not components
The first thing I build is never a button. It is a token layer: a small, opinionated set of named values for colour, spacing, radius, elevation, and type. Tokens are the vocabulary of the system, and every component that comes later is just a sentence written with that vocabulary. If you begin with components instead, you end up with forty variants of a card, each hard-coding its own shade of grey, and no way to change the brand without a two-week refactor.
I keep the token layer deliberately small. Three surface colours, one primary, one accent, one destructive, and a muted foreground will carry an entire product further than a fifty-swatch palette. Constraint is the feature. When a designer asks for a new colour, that request becomes a conversation about hierarchy rather than an unnoticed addition to a spreadsheet. Small systems get used; large systems get worked around.
Semantic naming matters more than the values themselves. A token called background tells you where it belongs; a token called grey-750 tells you nothing and quietly invites misuse. Semantic names also make theming almost free: swapping the values behind background, foreground, and border produces a credible dark mode without touching a single component file.
Components should encode decisions, not options
The most common failure I see is a component API that exposes every possible prop. A button that accepts colour, padding, font weight, and border radius is not a component — it is a styling escape hatch with a friendly name. Every option you expose is a decision you have pushed back onto the person in a hurry at 6pm on a Friday, and they will make it differently than you would.
Instead I ship variants. A primary variant, a quiet variant, a destructive variant, and perhaps one expressive variant for marketing surfaces. Each one bakes in the correct token combination, the right focus ring, and the correct disabled treatment. The call site becomes a statement of intent rather than a pile of utility classes, and code review turns into a conversation about meaning: is this action really primary?
Accessibility belongs inside the component too. Focus states, hit-target sizes, contrast pairings, reduced-motion fallbacks, and sensible ARIA defaults should be impossible to forget because nobody has to remember them. When accessibility lives in the component, an audit becomes a short list of exceptions instead of a rewrite of the entire interface.
Governance is the part everyone skips
Systems decay because no one owns them. I recommend a lightweight model: one accountable maintainer, a documented proposal path for new patterns, and a standing rule that any hard-coded value in a pull request must come with a comment explaining why the system could not serve it. Those comments are gold — read them monthly and they tell you exactly what to build next.
Documentation should live beside the code and show real usage, including the cases where a pattern is the wrong choice. I write a short ‘use this instead’ note for every deprecated component and leave it in place for a full release cycle. Migration is a social process, and people migrate faster when the alternative is obvious and the tone is generous rather than scolding.
Finally, measure adoption instead of admiring the library. Count how many screens render system components versus bespoke markup, track how often tokens get bypassed, and review those numbers with the team the way you would review performance metrics. A system that is adopted at forty per cent is not a design system; it is a suggestion. Once adoption crosses roughly eighty per cent, something quiet and valuable happens — visual consistency stops requiring effort, redesigns become configuration changes, and the team spends its energy on product problems again.
That is the real return on the investment. Not prettier buttons, but a shorter distance between a decision and a shipped interface, sustained over years rather than a single launch.