UI component library rules I follow
Component libraries drift fast when naming, states and responsibilities are left vague. Here, I set out the rules that keep reusable UI predictable, maintainable and ready to ship.
Checking read-aloud support…
A Component Library Fails When It Stops Being Predictable
Most component libraries do not become painful because they lack features.
They become painful because nobody is confident what a component is supposed to do anymore.
A card starts carrying layout responsibility it was never meant to own. A button variant appears because a one-off design needed it. A spacing decision gets duplicated across six components. State handling drifts. The naming becomes visual rather than semantic. Soon the library is technically reusable but practically unreliable.
That is why I care less about how many components exist and more about whether they are predictable.
One Component, One Clear Responsibility
A component should have a narrow enough role that another developer can understand it quickly.
If a component is trying to be a layout primitive, content container, interaction wrapper and marketing flourish at the same time, it becomes hard to reason about and hard to change safely.
So my first rule is simple:
A component should have one primary responsibility.
This is what keeps composition healthy. It allows a system to stay flexible without every component turning into a configuration object with too many hidden behaviours.
Design Tokens Should Live Above Components
When components carry their own ad hoc colours, spacing rules and type decisions, the system stops being a library and becomes a pile of isolated widgets.
That is why tokens matter.
Spacing, colour, radius, shadows, typography and breakpoints should be defined at a system level wherever possible. Components can then consume those values instead of re-inventing them.
This reduces drift and makes redesign work dramatically safer because the visual language is not trapped inside dozens of unrelated files.
Variants Should Be Explicit, Not Implied
One common failure mode is allowing components to infer too much from context.
A class name changes slightly and the component behaves differently. A slot is populated and now the spacing model changes. A modifier class appears in one template and gradually becomes permanent.
I prefer explicit variants with clear intent.
If a component has multiple supported forms, those forms should be named, documented and limited. Hidden behavioural branching is one of the quickest ways to make a UI system feel unstable.
Accessibility Should Not Be A Post-Render Patch
A reusable component that ignores keyboard behaviour, focus visibility or semantic structure is not really reusable. It is only visually repeatable.
So I treat accessibility concerns as part of the component contract:
- interactive states must be visible
- semantic HTML should lead the implementation
- keyboard use should be considered by default
- naming and labels should support assistive technology
This is not a separate quality pass after the fact. It is part of what makes a component trustworthy.
Naming Should Describe Purpose, Not Appearance
When components are named after what they look like instead of what they do, systems become brittle.
A name like BlueCardLarge does not age well because both the colour and the size may change. A name that describes purpose is usually more stable.
Examples of better naming tend to answer questions like:
- is this a content card or a navigation card
- is this a primary action or a secondary action
- is this a section wrapper or a layout grid
Purpose-based naming is easier to maintain because it survives design iteration better than appearance-based naming.
Shared Components Need Fewer Escape Hatches
A healthy library does not give every component endless override paths.
The more escape hatches you add, the less confidence anyone has that a component will render consistently across the site. At some point, you no longer have a component system. You have a styling engine disguised as one.
That does not mean components should be rigid to the point of uselessness. It means flexibility should be intentional and bounded.
Documentation Matters Because Memory Is Not A System
A small team can get away with informal conventions for a while. Then the project grows, someone returns to old code months later, and the undocumented assumptions become expensive.
Even lightweight documentation helps:
- what the component is for
- what props or variants are supported
- what it should not be used for
- what states must be tested
The goal is not documentation theatre. It is reducing relearning.
A Good Component Library Lowers Decision Fatigue
The best result of a component system is not just visual consistency. It is lower decision fatigue.
A developer should not need to solve typography, spacing and state treatment from scratch every time a new feature is built. The system should already make the safer choice easier.
That is what turns a component library into operational leverage rather than just shared markup.
Component Quality Is Really About Trust
When a UI library is healthy, people trust it.
They trust that a component will behave as documented. They trust that the states are visible. They trust that using the system is safer than improvising outside it.
That trust is what keeps the codebase calmer over time.
And in my experience, calm systems ship better.