Headless
The headless components ship behaviour, not looks. Each one wires up the keyboard interactions, the focus management, and the ARIA — and leaves every visual decision to you.
What headless means
A Dialog is more than a styled box. It traps focus, restores it on close, closes on Escape,
binds its title and description for screen readers, and manages an open state that can be
controlled or uncontrolled. That behaviour is the same in every app. The styling is not.
@usemotif/headless ships the behaviour and stops there. A headless component exposes a small
compositional API — Dialog.Root, Dialog.Trigger, Dialog.Content, and so on — and renders
unstyled elements. You bring the surface: a styled Box, your own tokens, your own layout. Motif
keeps the contract correct underneath.
Install
The headless components live in their own package:
Then import from it directly:
It is a separate install because most apps want to compose their own surfaces. Shipping the behaviour and the styling together would mean inheriting visual decisions you would only override.
The compound pattern
Headless components are compound — a Root that holds state and several named parts that read it
through context. You assemble the parts; the assembly is the API.
Each per-component page shows the full assembly in an Anatomy section, then documents every part in its own API entry.
The families
| Family | Behaviours |
|---|---|
| Overlay | Dialog, AlertDialog, Popover, HoverCard, Tooltip, Drawer, Sheet |
| Menu | Menu, ContextMenu, NavigationMenu, CommandPalette |
| Disclosure | Accordion, Collapsible, Tabs |
| Selection | Checkbox, RadioGroup, Switch, Combobox, MultiSelect, Search, Select |
| Date & time | Calendar, DatePicker, TimeInput |
| Numeric | Slider, RangeSlider, Progress, RatingInput |
| Feedback | Toast |
| Navigation | Breadcrumb, Pagination, Stepper, Toolbar |
| Specialized | ColorPicker, FileUpload, TreeView |
Headless and the primitives
Headless components compose the styled primitives underneath — a Dialog renders
through Portal, Overlay, and FocusScope. The two layers fit together: primitives are the
surface, headless is the behaviour, and your app supplies the styling that joins them.