A set of completely unstyled, fully accessible UI components for React, designed to integrate beautifully with Tailwind CSS.
@headlessui/react is a comprehensive library of unstyled, accessible UI components built specifically for React applications. Created by the Tailwind Labs team, it solves the common problem of building custom-styled interfaces while maintaining proper accessibility standards. Unlike traditional component libraries that come with opinionated styling, Headless UI provides the behavior, keyboard interactions, focus management, and ARIA attributes while leaving visual design entirely to you.
The library implements complex UI patterns that are notoriously difficult to get right—dialogs with focus trapping, comboboxes with keyboard navigation, disclosure panels with smooth transitions, and more. Each component follows WAI-ARIA guidelines and handles edge cases that developers often miss when building from scratch. This approach lets you build interfaces that look exactly how you want while ensuring they work correctly for all users, including those using assistive technologies.
With over 4 million weekly downloads, @headlessui/react has become a go-to solution for teams building design systems and custom interfaces. It's particularly popular in applications using Tailwind CSS, though it works with any styling solution including CSS Modules, styled-components, or plain CSS. The library uses a render prop pattern and exposes component state through data attributes, giving you complete control over conditional rendering and styling based on interaction states like hover, focus, and active.
import { useState } from 'react'
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
function UserSettingsModal() {
const [isOpen, setIsOpen] = useState(false)
const [notifications, setNotifications] = useState(true)
function handleSave() {
// Save settings to API
console.log({ notifications })
setIsOpen(false)
}
return (
<>
<button
onClick={() => setIsOpen(true)}
className="rounded-md bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
>
Open Settings
</button>
<Transition show={isOpen}>
<Dialog onClose={() => setIsOpen(false)} className="relative z-50">
<TransitionChild
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/30" aria-hidden="true" />
</TransitionChild>
<div className="fixed inset-0 flex items-center justify-center p-4">
<TransitionChild
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<DialogPanel className="w-full max-w-md rounded-lg bg-white p-6 shadow-xl">
<DialogTitle className="text-lg font-semibold mb-4">
User Settings
</DialogTitle>
<div className="space-y-4">
<label className="flex items-center gap-3">
<input
type="checkbox"
checked={notifications}
onChange={(e) => setNotifications(e.target.checked)}
className="h-4 w-4"
/>
<span>Enable email notifications</span>
</label>
</div>
<div className="mt-6 flex gap-3 justify-end">
<button
onClick={() => setIsOpen(false)}
className="px-4 py-2 rounded border hover:bg-gray-50"
>
Cancel
</button>
<button
onClick={handleSave}
className="px-4 py-2 rounded bg-blue-600 text-white hover:bg-blue-700"
>
Save Changes
</button>
</div>
</DialogPanel>
</TransitionChild>
</div>
</Dialog>
</Transition>
</>
)
}Custom Design Systems: Teams building proprietary design systems use Headless UI as the accessible foundation, applying their own brand styling on top. This is faster than building accessible components from scratch and more flexible than adapting pre-styled libraries.
E-commerce Product Filters: Complex filter interfaces with multiple select dropdowns, disclosure panels for categories, and dialog modals for advanced options benefit from Headless UI's keyboard navigation and focus management without fighting against unwanted default styles.
Dashboard Command Palettes: Building command-k style interfaces requires robust combobox behavior with keyboard shortcuts, filtering, and proper ARIA announcements—all provided by the Combobox component while you control the visual presentation.
Mobile-First Form Interfaces: Creating custom select inputs, switches, and radio groups that match your mobile app's design while maintaining accessibility across devices and input methods (touch, mouse, keyboard).
Marketing Sites with Interactive Elements: Landing pages that need custom-styled popovers, tooltips, and disclosure sections that animate smoothly and work correctly with screen readers without including entire component library bundles.
npm install @headlessui/reactpnpm add @headlessui/reactbun add @headlessui/react