Menu, Dialog & Listbox
What "Headless" Means
Behavior, state, and accessibility (ARIA roles, keyboard nav, focus management) with zero built-in visual styling — you own every class/style. Built by the Tailwind team, pairs naturally with Tailwind utilities, but works with any CSS approach since it applies no styles itself.
Menu (Dropdown)
import { Menu } from '@headlessui/react'
function MyMenu() {
return (
<Menu>
<Menu.Button className="btn">Options</Menu.Button>
<Menu.Items className="dropdown-panel">
<Menu.Item>
{({ active }) => (
<a className={active ? 'bg-blue-500' : ''} href="/edit">Edit</a>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<a className={active ? 'bg-blue-500' : ''} href="/delete">Delete</a>
)}
</Menu.Item>
</Menu.Items>
</Menu>
)
}Menu/Menu.Button/Menu.Items/Menu.Item is a compound-component pattern. The render-prop { active } exposes internal state so you can style the highlighted item without managing that state yourself.
Dialog (Modal)
Handles focus trapping while open, Escape/outside-click to close, and restoring focus to the trigger element on close — the subtle accessibility behaviors easy to get wrong hand-rolling a modal.
Listbox — Stylable Select
Native <select> is accessible but can't be deeply restyled cross-browser. Listbox reimplements the same accessible pattern (same keyboard behavior as a native select) while being fully custom-stylable.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free