A set of completely unstyled, fully accessible UI components for React, designed to integrate beautifully with Tailwind CSS.
npx @tessl/cli install tessl/npm-headlessui--react@2.2.0Headless UI is a set of completely unstyled, fully accessible UI components for React, designed to integrate beautifully with Tailwind CSS. The components provide the behavioral logic and accessibility features for complex UI patterns while giving developers complete control over styling.
npm install @headlessui/reactimport {
Button,
Checkbox,
CloseButton,
Input,
Select,
Textarea,
Dialog,
DialogPanel,
DialogBackdrop,
DialogTitle,
Menu,
MenuButton,
MenuItems,
MenuItem,
Combobox,
ComboboxInput,
ComboboxButton,
ComboboxOptions,
ComboboxOption,
Listbox,
ListboxButton,
ListboxOptions,
ListboxOption,
Popover,
PopoverButton,
PopoverPanel,
Switch,
TabGroup,
TabList,
Tab,
TabPanels,
TabPanel,
Radio,
RadioGroup,
RadioGroupOption,
Disclosure,
DisclosureButton,
DisclosurePanel,
Field,
Fieldset,
Legend,
Label,
Description,
FocusTrap,
Portal,
Transition,
DataInteractive,
useClose
} from "@headlessui/react";For CommonJS:
const {
Button,
Checkbox,
CloseButton,
Input,
Select,
Textarea,
Dialog,
DialogPanel,
DialogBackdrop,
DialogTitle,
Menu,
MenuButton,
MenuItems,
MenuItem,
Combobox,
ComboboxInput,
ComboboxButton,
ComboboxOptions,
ComboboxOption,
Listbox,
ListboxButton,
ListboxOptions,
ListboxOption,
Popover,
PopoverButton,
PopoverPanel,
Switch,
TabGroup,
TabList,
Tab,
TabPanels,
TabPanel,
Radio,
RadioGroup,
RadioGroupOption,
Disclosure,
DisclosureButton,
DisclosurePanel,
Field,
Fieldset,
Legend,
Label,
Description,
FocusTrap,
Portal,
Transition,
DataInteractive,
useClose
} = require("@headlessui/react");import { useState } from "react";
import { Dialog, DialogPanel, DialogTitle } from "@headlessui/react";
function MyDialog() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>Open dialog</button>
<Dialog open={isOpen} onClose={() => setIsOpen(false)}>
<div className="fixed inset-0 bg-black/30" aria-hidden="true" />
<div className="fixed inset-0 flex w-screen items-center justify-center p-4">
<DialogPanel className="max-w-lg space-y-4 bg-white p-6 rounded-lg">
<DialogTitle className="font-bold">Confirm Action</DialogTitle>
<p>Are you sure you want to continue?</p>
<div className="flex gap-4">
<button onClick={() => setIsOpen(false)}>Cancel</button>
<button onClick={() => setIsOpen(false)}>Confirm</button>
</div>
</DialogPanel>
</div>
</Dialog>
</>
);
}Headless UI follows several key design principles:
asBasic form controls including buttons, inputs, checkboxes, selects, textareas, and switches with built-in accessibility and interaction states.
// Basic button with interaction states
function Button(props: ButtonProps): JSX.Element;
// Checkbox with indeterminate state support
function Checkbox(props: CheckboxProps): JSX.Element;
// Text input with validation states
function Input(props: InputProps): JSX.Element;
// Native select element with enhanced styling
function Select(props: SelectProps): JSX.Element;
// Textarea element with form integration
function Textarea(props: TextareaProps): JSX.Element;
// Toggle switch component
function Switch(props: SwitchProps): JSX.Element;Advanced selection interfaces including comboboxes, listboxes, radio groups, and native selects with keyboard navigation and accessibility.
// Autocomplete combobox with filtering
function Combobox<TValue>(props: ComboboxProps<TValue>): JSX.Element;
// Multi-select capable listbox
function Listbox<TValue>(props: ListboxProps<TValue>): JSX.Element;
// Radio button group for single selection
function RadioGroup<TValue>(props: RadioGroupProps<TValue>): JSX.Element;Modal dialogs, popovers, and tooltips that appear on top of the main content with focus management and portal rendering.
// Modal dialog with focus trapping
function Dialog(props: DialogProps): JSX.Element;
// Floating popover interface
function Popover(props: PopoverProps): JSX.Element;
// Tooltip component (commented out in v2.2.7)
// function Tooltip(props: TooltipProps): JSX.Element;Components for organizing and navigating content including menus, tabs, and disclosure panels.
// Dropdown menu for actions
function Menu(props: MenuProps): JSX.Element;
// Tab interface for content organization
function TabGroup(props: TabGroupProps): JSX.Element;
// Collapsible disclosure panel
function Disclosure(props: DisclosureProps): JSX.Element;Supporting components and utilities including focus traps, portals, labels, descriptions, transitions, and hooks.
// Focus management utility
function FocusTrap(props: FocusTrapProps): JSX.Element;
// Portal for rendering outside DOM tree
function Portal(props: PortalProps): JSX.Element;
// CSS transition wrapper
function Transition(props: TransitionProps): JSX.Element;
// Form label with automatic association
function Label(props: LabelProps): JSX.Element;
// Description text with automatic association
function Description(props: DescriptionProps): JSX.Element;
// Hook for closing containing components
function useClose(): () => void;All interactive components provide render props with current interaction state:
<Button>
{({ hover, focus, active, disabled }) => (
<span
className={`
px-4 py-2 rounded
${hover ? 'bg-blue-100' : 'bg-white'}
${focus ? 'ring-2 ring-blue-500' : ''}
${active ? 'bg-blue-200' : ''}
${disabled ? 'opacity-50 cursor-not-allowed' : ''}
`}
>
Click me
</span>
)}
</Button>Use the
as// Render as a link instead of button
<Button as="a" href="/dashboard">
Dashboard
</Button>
// Render as a custom component
<Button as={CustomLink} to="/profile">
Profile
</Button>Form components integrate with standard HTML form patterns:
<form>
<Field>
<Label>Username</Label>
<Input name="username" required />
<Description>Enter your username</Description>
</Field>
<Field>
<Checkbox name="newsletter" value="yes">
Subscribe to newsletter
</Checkbox>
</Field>
</form>// Common render prop types
interface InteractionState {
hover: boolean;
focus: boolean;
active: boolean;
disabled: boolean;
}
// Polymorphic component props
interface PolymorphicProps<TTag extends keyof JSX.IntrinsicElements = 'div'> {
as?: TTag;
children?: React.ReactNode | ((props: any) => React.ReactNode);
}
// Focus trap features enum
enum FocusTrapFeatures {
None = 0,
InitialFocus = 1,
TabLock = 2,
FocusLock = 4,
RestoreFocus = 8,
AutoFocus = 16
}
// Comparison function type for value-based components
type ByComparator<T> =
| ((a: T, z: T) => boolean)
| keyof T
| null;Some components have been deprecated in favor of more flexible alternatives:
Form Organization:
SwitchGroupFieldSwitchLabelLabelSwitchDescriptionDescriptionRadio Groups:
RadioGroupLabelLabelRadioGroupDescriptionDescriptionLegacy Subcomponent Patterns:
Combobox.InputComboboxInputCombobox.ButtonComboboxButtonCombobox.OptionsComboboxOptionsCombobox.OptionComboboxOptionMenu.ButtonMenuButtonMenu.ItemsMenuItemsMenu.ItemMenuItemListbox.ButtonListboxButtonListbox.OptionsListboxOptionsListbox.OptionListboxOptionDialog.PanelDialogPanelDialog.TitleDialogTitleDisclosure.ButtonDisclosureButtonDisclosure.PanelDisclosurePanelThis documentation covers @headlessui/react v2.2.7. Some features may differ in earlier versions:
ComboboxInputMenuButtonasFieldFieldsetSome components are planned but not yet available:
Tooltip