AI Features

Headless Component APIs

Learn how to design headless components that expose behavior without prescribing UI, splitting logic from presentation, and combining it with compound component patterns for maximum flexibility.

As React applications mature, teams often start extracting reusable UI components such as dropdowns, modals, tooltips, tabs, and accordions. At first, this feels like progress: centralized behavior, fewer bugs, and consistent interactions. But over time, friction appears.

A dropdown component works well on one screen, but on another the design requires a different button style. A product team wants custom animations. Marketing needs a different layout structure. Accessibility improvements require changing markup order. Suddenly, the “reusable” component becomes rigid. Developers start adding props like variant="compact" or renderCustomItem. Conditional branches multiply. Styling overrides leak into the component. The abstraction collapses under conflicting presentation needs.

The root problem is architectural: the component couples logic and UI. Behavior (keyboard navigation, open/close state, focus management, ARIA attributes) is tightly bound to markup and styling. Any change to presentation risks breaking interaction logic. Reuse becomes constrained by the original visual decisions.

In React 19, where rendering is concurrent and composition is a core design strength, we can solve this differently. Instead of building UI components that happen to contain logic, we build logic components that expose state and behavior. The UI becomes a consumer of that logic. This is the headless component pattern.

The problem we’re solving in this lesson is not how to build a dropdown. We’re solving for how to design reusable interaction logic that powers many visual implementations without duplication or rigidity.

Headless components isolate interaction logic from visual structure, enabling flexible composition without duplicating behavior
Headless components isolate interaction logic from visual structure, enabling flexible composition without duplicating behavior

Reusable behavior APIs with flexible UI composition

A headless component exposes behavior, not markup. In a traditional component, we return JSX that includes structure, styling hooks, and interaction handlers. In a headless component, we return state and event bindings. The caller decides how to render them. This separation creates two layers:

  • Behavior layer: owns state, keyboard interactions, focus management, accessibility semantics, and controlled or uncontrolled logic.

  • Presentation layer: controls layout, styles, animation, and visual structure.

A headless component does not render DOM directly. Instead, it provides an API, often through hooks or compound components, that consumers use to attach behavior to their own markup. A second architectural concept is the compound component structure. Instead of passing dozens of props down, we group related pieces under a shared context. For example:

  • <Dropdown>

  • <Dropdown.Trigger>

  • <Dropdown.Menu>

  • <Dropdown.Item>

Internally, these pieces share state through context. Externally, the consumer controls layout and styling. This pattern enables maximum flexibility:

  • Different visual structures can reuse the same behavior.

  • Styling systems remain independent.

  • Interaction logic stays centralized and testable.

  • Accessibility can be enforced in the behavior layer.

In React 19 terms, this aligns with the composition-first design principle. Rendering remains declarative, while state coordination happens inside a controlled boundary. The mental shift is important. We are not building UI components. We are building behavior APIs that UI can consume.

Example: Headless dropdown behavior is shared, UI is replaceable

Now we’ll prove the mental model by building a headless dropdown menu where:

  • The dropdown exposes logic and accessibility bindings but does not prescribe UI.

  • Presentation is implemented in separate components using the headless API. ...