Interface Lab
Back to knowledge
Frontend Implementation

Primitive Component Selection

When an interaction involves focus, keyboard behavior, overlays, arrow keys, or screen-reader semantics, start from a mature primitive and apply local visuals.

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

  1. Radix Primitives fit React components that need fine-grained focus control, collision positioning, arrow keys, and ARIA patterns.
  2. Headless UI fits Tailwind, React, and Vue projects with well-scoped unstyled accessible components.
  3. Choosing a primitive does not replace the design system. It connects visual tokens, variants, and layout rules to stable behavior.
  4. 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.