Back to all posts

The Three-Layer Rule for Design Systems

Pranay Kothapalli
Pranay Kothapalli

Maintainer at Rad UI

4 min read

A framework for keeping your design system sane: Primitives, Components, and Compositions — where each layer lives and why mixing them creates chaos.

The Three-Layer Rule for Design Systems

Every design system that survives more than one product cycle eventually stumbles into the same question:
What belongs where?

When a new button variant creeps into your PR, or a designer renames “Primary / Large” to “Default / Big”, it’s not the naming that kills you — it’s the blurring of layers. The architecture collapses when your building blocks forget what level they’re on.

That’s why I like to think of every design system in three layers:
Primitives → Components → Compositions.

Everything you build fits somewhere in this hierarchy. Knowing which layer you’re working in — and keeping it there — prevents chaos.


1. Primitives: The Atoms of Interaction

Primitives are your low-level elements: buttons without opinion, modals without makeup, menus without style. They do one thing — behave correctly.

If your primitive is a button, it shouldn’t know what “primary” means.
If your primitive is a dialog, it shouldn’t care about your brand’s border radius.

Think of primitives as contracts, not components. They define what something is capable of, not what it looks like. In React terms, these are your @radix-ui/react-* equivalents — focus management, accessibility wiring, keyboard handling, escape key behavior.

When you build primitives right, they outlive every rebrand and every Figma update. They’re the last layer you’ll ever want to rewrite.


2. Components: The Language of the Brand

If primitives are atoms, components are molecules with taste.
They combine primitives with design tokens to express your brand’s visual voice.

A Button here is not just interactive — it’s your button. It knows its background color, its hover tone, its animation curve. It’s opinionated by design, but those opinions flow from the system’s tokens, not from inline CSS or ad hoc props.

This is the layer where teams often get greedy. They keep stuffing features into components — more props, more variants, more conditional logic — until the API becomes a kitchen sink.

That’s a code smell. When your component starts asking for ten boolean props to look right, it’s screaming to be decomposed or lifted up to the next layer.


3. Compositions: The Stories We Actually Ship

Compositions are where product meets system.
They’re the patterns your users actually interact with: a SignupForm, a Sidebar, a ToastStack.

These are built out of components, not by mutating them.
No design system should ship a “SignupForm” — that’s the app’s responsibility. But your system should make composing one trivial.

The purpose of compositions is velocity. You take the primitives that guarantee correct behavior, combine them through branded components, and compose them into flows that feel coherent across the product.

The best compositions barely look designed — they just fit. Because the system behind them is doing its job invisibly.


Why the Layers Matter

Teams get into trouble when these layers start leaking.

  • A primitive that knows about brand colors? You’ve broken abstraction.
  • A component that tries to handle business logic? You’ve blurred ownership.
  • A composition that directly uses primitives? You’ve skipped the visual language of your brand.

Each layer has its own source of truth:

  • Primitives depend on accessibility and interaction patterns.
  • Components depend on tokens and theme systems.
  • Compositions depend on product context.

Mix them, and your design system turns into an archaeological dig — full of props no one understands and overrides no one dares touch.


The Three-Layer Rule in Practice

When we built Rad UI, we formalized this separation:

  • Primitives: Headless, accessible, behavior-only React components.
  • Components: Styled, theme-aware versions built on primitives.
  • Compositions: Patterns that live in the documentation or app layer, never the package.

This structure isn’t just tidy — it’s future-proof. When your startup inevitably rebrands (and it will), you’ll be grateful that your primitives don’t know anything about color, and your components don’t know anything about marketing’s latest gradient obsession.


The Philosophy in One Line

Design systems aren’t about consistency.
They’re about containment.

Keep behaviors in primitives.
Keep aesthetics in components.
Keep products in compositions.

That’s how you build a system that survives two rebrands and still feels coherent on the third.


If your design system feels like it’s collapsing under its own weight, check your layers. The chaos isn’t random — it’s just leaking upward.