Primitives are leverage
Most UI systems don't fail because of sloppy styling or inconsistent spacing. They fail because the primitives are too specific.
When a primitive encodes a product concept instead of a capability, the system stops bending. Every new requirement forces either duplication or an exception, and the UI layer slowly turns into a graveyard of one-off components. Strong primitives are boring by design, and that's exactly why they last.
What makes a good primitive
A good primitive is reusable: it appears in different contexts without modification. It's composable: it gains meaning when combined with other primitives, not on its own. And it's context-agnostic: it doesn't know or care why it's being used.
A primitive should describe what something is, not why it exists. The moment it starts answering product questions, it stops being a primitive.
The cost of specificity
Specific primitives feel productive at first. They move fast, they read well in a diff. Then they lock you in.
Names like
HomeHeroCard, TrendingDestinationTile, or PromoBannerV3 bake placement, intent, and version into the component itself. All three of those things change eventually, and when they do, the primitive becomes either misleading or dead weight. Specificity ages badly.Boring primitives win
Good primitives are deliberately generic: Card, Media, Title, Action, Badge. Alone, each one looks underwhelming. Put together, they say something.
Meaning comes from composition, not from a special-purpose component. A "Trending Destination" isn't a primitive. It's a Card with Media, a Title, a couple of Badges, and an Action. If the concept changes tomorrow, none of the underlying pieces need to move.
Primitives enable everything else
Once the primitive layer is solid, a lot of higher-level work falls out for free. Server-driven UI becomes possible because primitives form a stable rendering vocabulary. Cross-platform rendering works because primitives map cleanly onto platform-specific views. Agent-driven interfaces work because an agent can reason in primitives instead of screens. Experimentation gets cheap because composition changes without touching infrastructure.
None of that is a design-system concern. It's infrastructure.
Evolution without rewrites
Good primitive systems are asymmetric: primitives change slowly, composition changes fast. That asymmetry is the point. When primitives are stable, experiments stay cheap, features evolve without a rewrite, and old layouts can sit next to new ones without conflict.
Most UI rewrites don't happen because the design changed. They happen because the primitives were too specific to survive the change in the first place.
Designing for longevity
If you find yourself reaching for
V2, New, or Updated in a primitive's name, that's usually a sign the abstraction underneath it is wrong. A primitive should be minimal, predictable, and hard to misuse. If it's easy to misuse, it's probably doing too much.