Back to all posts

Ten Commandments for Headless UI Libraries

Pranay Kothapalli
Pranay Kothapalli

Maintainer at Rad UI

4 min read

What separates a great headless UI library from a forgettable one — the ten laws every design system builder should follow.

Ten Commandments for Headless UI Libraries

Headless UI libraries are the unsung skeletons of modern web apps.
They don’t flash colors or animate gradients — they just work, letting your design system shine without stealing the spotlight.

But building one is deceptively hard.
Get the abstractions wrong and you’ll spend the next two years explaining why your Modal doesn’t trap focus.

After working on Rad UI, studying Radix, Headless UI, and React Aria, I’ve distilled what I consider the Ten Commandments of headless component design.


1. Thou shalt separate logic from style

The first rule of headless UI: keep your logic pure.
Every bit of DOM structure, ARIA state, and keyboard handling must work flawlessly without assuming how the component looks.

If you can’t drop your component into a blank HTML page and still have it behave perfectly, you’ve built a styled library, not a headless one.


2. Thou shalt be accessible by default

Accessibility isn’t an optional plugin; it’s the core engine.
Your components should pass axe-core without a single complaint.
If you don’t understand focus management, roving tabindex, or ARIA relationships — learn them before writing a single line of code.

Accessibility is not “extra work.” It’s interface physics.


3. Thou shalt expose composable primitives

Don’t ship opinionated “mega components.”
Expose the atoms — Dialog.Root, Dialog.Trigger, Dialog.Content — and let developers wire them together.
Composition > configuration. Always.

A flexible primitive lasts longer than a fancy prop API.


4. Thou shalt document the invisible

Headless UI isn’t flashy, so the docs have to overcompensate.
Explain why each prop exists, when to use each sub-component, and how it behaves under stress (focus traps, nested modals, portals).
The invisible deserves excellent documentation.


5. Thou shalt not mutate the DOM

If your component modifies the DOM outside React’s control — you’ve angered the React gods.
Use refs, portals, and controlled state. No document.querySelector sacrifices.


6. Thou shalt respect design systems

A headless library should fit into any design system like water into glass.
Expose asChild or render props to let teams wrap components in their own elements.
Never force them to adopt your spacing scale, color tokens, or motion system.


7. Thou shalt optimize for DX (Developer Experience)

APIs should feel like they were discovered, not invented.
Good headless components read naturally:


<Popover>
  <Popover.Trigger>Open</Popover.Trigger>
  <Popover.Content>Hi there.</Popover.Content>
</Popover>

Developers should feel like they’re writing React, not deciphering React.


8. Thou shalt test interactions, not snapshots

Snapshot tests lie. What matters is whether keyboard navigation, pointer events, and focus order behave correctly. Use @testing-library/react and user-event to simulate reality — because your users will.


9. Thou shalt version with care

When you change the internal behavior of a primitive, treat it like a breaking API. Headless components are the foundation of design systems — a single regression can ripple through dozens of downstream components. Version early, version clearly, version safely.


10. Thou shalt embrace detachment

Every great headless library should offer an escape hatch — a way to detach styles, themes, or even DOM structure. Developers should be able to extend or override your components without forking the library. The goal isn’t control — it’s freedom.


Epilogue: Beyond the commandments

Headless UI is the art of restraint. It’s saying “no” to shiny defaults so others can say “yes” to their own taste.

Follow these commandments and you’ll build components that don’t just render — they last.


Building your own headless library? You might like what we’re doing at Rad UI — a headless component library built for modern design systems.