Design Principle
The risk in complex interactive components is usually not styling. It is focus management, keyboard paths, ARIA semantics, portals, collision positioning, and mobile scroll locking. Primitives stabilize that behavior first.
Large Theory
Accessible interaction components should solve the behavior contract before visual expression. Dialogs, menus, popovers, tabs, accordions, selects, and sliders are easy to get wrong when built from scratch because keyboard, focus return, screen-reader labels, and touch behavior are often missed.
Small Points
- Radix Primitives fit React components that need fine-grained focus control, collision positioning, arrow keys, and ARIA patterns.
- Headless UI fits Tailwind, React, and Vue projects with well-scoped unstyled accessible components.
- Choosing a primitive does not replace the design system. It connects visual tokens, variants, and layout rules to stable behavior.
- After a primitive enters the project, loading, empty, error, disabled, reduced-motion, and mobile states still need local design.
Design Judgment
If a component needs focus trap, Escape close, focus return, arrow-key movement, or screen-reader semantics, do not start with a div-only version. First check whether Radix or Headless UI covers the behavior.
Implementation Notes
Record component selection with user task, candidate primitive, required states, keyboard path, ARIA constraints, style tokens, mobile differences, and test points. Expose only product-level props instead of leaking the primitive API into pages.
Counterexamples/Risks
A hand-written dropdown that only works with mouse, a dialog that loses focus on close, a popover that hides its trigger on mobile, tabs without arrow navigation, and selects that show selection only through color.
Case Study
Radix Primitives positions itself as unstyled, accessible, open-source React primitives and demonstrates behavior for Dialog, Dropdown Menu, Popover, Slider, Tabs, and more. Headless UI similarly emphasizes unstyled and accessible components. The reusable lesson is to let mature primitives own behavior complexity while local components own brand and product semantics.
Source Links
Radix Primitives: https://www.radix-ui.com/primitives Radix GitHub: https://github.com/radix-ui/primitives Headless UI: https://headlessui.com/ Headless UI GitHub: https://github.com/tailwindlabs/headlessui
Agent Directive
For complex interactive components, list behavior requirements first, then choose Radix, Headless UI, or a native control, and only then style variants.