headlessui
Headless UI - Unstyled, fully accessible UI components for React and Vue with built-in ARIA patterns
What this skill does
# Headless UI - Accessible Component Primitives
## Overview
Headless UI provides completely unstyled, fully accessible UI components designed to integrate beautifully with Tailwind CSS. Built by the Tailwind Labs team, it offers production-ready accessibility without imposing design decisions.
**Key Features**:
- Fully unstyled - bring your own styles
- Complete keyboard navigation
- Screen reader tested
- Focus management
- ARIA attributes handled automatically
- TypeScript support
- React 18 and Vue 3 compatible
- SSR compatible
- Render props for maximum flexibility
**Installation**:
```bash
# React
npm install @headlessui/react
# Vue
npm install @headlessui/vue
```
## Component Catalog
### Menu (Dropdown)
Accessible dropdown menus with keyboard navigation and ARIA support.
```tsx
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
function DropdownMenu() {
return (
<Menu>
<MenuButton className="inline-flex items-center gap-2 rounded-md bg-gray-800 py-1.5 px-3 text-sm/6 font-semibold text-white shadow-inner shadow-white/10 focus:outline-none data-[hover]:bg-gray-700 data-[open]:bg-gray-700 data-[focus]:outline-1 data-[focus]:outline-white">
Options
<ChevronDownIcon className="size-4 fill-white/60" />
</MenuButton>
<MenuItems
transition
anchor="bottom end"
className="w-52 origin-top-right rounded-xl border border-white/5 bg-white/5 p-1 text-sm/6 text-white transition duration-100 ease-out [--anchor-gap:var(--spacing-1)] focus:outline-none data-[closed]:scale-95 data-[closed]:opacity-0"
>
<MenuItem>
<button className="group flex w-full items-center gap-2 rounded-lg py-1.5 px-3 data-[focus]:bg-white/10">
Edit
</button>
</MenuItem>
<MenuItem>
<button className="group flex w-full items-center gap-2 rounded-lg py-1.5 px-3 data-[focus]:bg-white/10">
Duplicate
</button>
</MenuItem>
<div className="my-1 h-px bg-white/5" />
<MenuItem>
<button className="group flex w-full items-center gap-2 rounded-lg py-1.5 px-3 data-[focus]:bg-white/10">
Delete
</button>
</MenuItem>
</MenuItems>
</Menu>
)
}
```
**Menu Features**:
- Arrow key navigation
- Type-ahead search
- Automatic focus management
- Escape to close
- Click outside to close
- Portal rendering for positioning
- Anchor positioning API
### Listbox (Select)
Custom select/dropdown component with full keyboard support.
```tsx
import { Listbox, ListboxButton, ListboxOptions, ListboxOption } from '@headlessui/react'
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid'
import { useState } from 'react'
const people = [
{ id: 1, name: 'Wade Cooper' },
{ id: 2, name: 'Arlene Mccoy' },
{ id: 3, name: 'Devon Webb' },
]
function SelectExample() {
const [selected, setSelected] = useState(people[0])
return (
<Listbox value={selected} onChange={setSelected}>
<ListboxButton className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white/75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm">
<span className="block truncate">{selected.name}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</span>
</ListboxButton>
<ListboxOptions className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm">
{people.map((person) => (
<ListboxOption
key={person.id}
value={person}
className="relative cursor-default select-none py-2 pl-10 pr-4 data-[focus]:bg-amber-100 data-[focus]:text-amber-900"
>
{({ selected }) => (
<>
<span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
{person.name}
</span>
{selected && (
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600">
<CheckIcon className="h-5 w-5" aria-hidden="true" />
</span>
)}
</>
)}
</ListboxOption>
))}
</ListboxOptions>
</Listbox>
)
}
```
**Listbox Features**:
- Single and multiple selection modes
- Type-ahead search
- Arrow key navigation
- Controlled and uncontrolled modes
- Disabled options support
- Custom value comparison
### Combobox (Autocomplete)
Searchable select component with filtering.
```tsx
import { Combobox, ComboboxInput, ComboboxOptions, ComboboxOption } from '@headlessui/react'
import { useState } from 'react'
const people = [
{ id: 1, name: 'Wade Cooper' },
{ id: 2, name: 'Arlene Mccoy' },
{ id: 3, name: 'Devon Webb' },
{ id: 4, name: 'Tom Cook' },
]
function AutocompleteExample() {
const [selected, setSelected] = useState(people[0])
const [query, setQuery] = useState('')
const filtered =
query === ''
? people
: people.filter((person) =>
person.name.toLowerCase().includes(query.toLowerCase())
)
return (
<Combobox value={selected} onChange={setSelected}>
<ComboboxInput
className="w-full rounded-lg border-none bg-white/5 py-1.5 pr-8 pl-3 text-sm/6 text-white focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25"
displayValue={(person) => person?.name}
onChange={(event) => setQuery(event.target.value)}
/>
<ComboboxOptions className="w-[var(--input-width)] rounded-xl border border-white/5 bg-white/5 p-1 [--anchor-gap:var(--spacing-1)] empty:invisible">
{filtered.map((person) => (
<ComboboxOption
key={person.id}
value={person}
className="group flex cursor-default items-center gap-2 rounded-lg py-1.5 px-3 select-none data-[focus]:bg-white/10"
>
<CheckIcon className="invisible size-4 fill-white group-data-[selected]:visible" />
<div className="text-sm/6 text-white">{person.name}</div>
</ComboboxOption>
))}
</ComboboxOptions>
</Combobox>
)
}
```
**Combobox Features**:
- Text input with filtering
- Keyboard navigation
- Nullable/optional selections
- Custom display values
- Async data loading support
- Multiple selection mode
### Dialog (Modal)
Accessible modal dialogs with focus trapping.
```tsx
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
import { Fragment, useState } from 'react'
function ModalExample() {
const [isOpen, setIsOpen] = useState(false)
return (
<>
<button onClick={() => setIsOpen(true)}>Open dialog</button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={() => setIsOpen(false)}>
<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black/25" />
</TransitionChild>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
Related in universal
mpm-orchestration-demo
IncludedReference implementation demonstrating the Command → Agent → Skill orchestration pattern in Claude MPM, showing both preloaded-skill and dynamic-skill-invocation styles
kubernetes
IncludedKubernetes operations playbook for deploying services: core objects, probes, resource sizing, safe rollouts, and fast kubectl debugging
opentelemetry
IncludedOpenTelemetry observability patterns: traces, metrics, logs, context propagation, OTLP export, Collector pipelines, and troubleshooting
threat-modeling
IncludedThreat modeling workflow for software systems: scope, data flow diagrams, STRIDE analysis, risk scoring, and turning mitigations into backlog and tests
terraform
IncludedTerraform infrastructure-as-code workflow patterns: state and environments, module design, safe plan/apply, drift control, and CI guardrails
sec-edgar-pipeline
IncludedSEC EDGAR extraction pipeline: setup, filing discovery by CIK, recipe-driven extraction, and report generation.