# Headless UI
Headless UI is a collection of completely unstyled, fully accessible UI components for React and Vue, designed to integrate seamlessly with Tailwind CSS. The library provides essential interactive components like menus, dialogs, listboxes, comboboxes, and more, implementing WAI-ARIA design patterns for accessibility. Components are "headless" meaning they provide functionality and accessibility without imposing any styling, giving developers complete control over the visual presentation while handling complex state management, keyboard navigation, focus management, and screen reader support automatically.
The library is distributed as three npm packages: `@headlessui/react` for React applications (currently v2.2.9), `@headlessui/vue` for Vue 3 applications, and `@headlessui/tailwindcss` as a Tailwind CSS plugin that provides utility variants for styling components based on their internal state. All components support both controlled and uncontrolled modes, work seamlessly with form submissions, and offer flexible APIs through render props, allowing developers to access internal component state for conditional rendering and dynamic styling. The components handle edge cases like scroll locking, focus trapping, click-outside detection, and proper cleanup automatically.
## Installation
### React Installation
```bash
npm install @headlessui/react
```
```jsx
import { Menu, Dialog, Listbox } from '@headlessui/react'
function App() {
return (
)
}
```
### Vue Installation
```bash
npm install @headlessui/vue
```
```vue
```
### Tailwind CSS Plugin Installation
```bash
npm install @headlessui/tailwindcss
```
```js
// tailwind.config.js
module.exports = {
plugins: [
require('@headlessui/tailwindcss'),
// Or with custom prefix
require('@headlessui/tailwindcss')({ prefix: 'ui' })
]
}
```
## Button Component
Accessible button with state management for hover, focus, active, and disabled states
```jsx
import { Button } from '@headlessui/react'
function ActionButton() {
return (
)
}
// With render prop for state-based styling
function StatefulButton() {
return (
)
}
// Button types
function FormButtons() {
return (
)
}
```
## Checkbox Component
Accessible checkbox with indeterminate state support and form integration
```jsx
import { Checkbox, Field, Label, Description } from '@headlessui/react'
import { useState } from 'react'
function TermsCheckbox() {
const [enabled, setEnabled] = useState(false)
return (
)
}
// Indeterminate checkbox
function SelectAllCheckbox() {
const [selectedItems, setSelectedItems] = useState([])
const items = ['Item 1', 'Item 2', 'Item 3']
const allSelected = selectedItems.length === items.length
const someSelected = selectedItems.length > 0 && !allSelected
return (
>
)}
)
}
// With backdrop overlay
function PopoverWithBackdrop() {
return (
Open Menu
Menu
Content goes here
)
}
```
## Disclosure Component
Show/hide component for accordions and expandable sections
```jsx
import { Disclosure } from '@headlessui/react'
function FAQ() {
const faqs = [
{
question: 'What is your refund policy?',
answer: 'If you\'re unhappy with your purchase for any reason, email us within 90 days and we\'ll refund you in full, no questions asked.',
},
{
question: 'Do you offer technical support?',
answer: 'Yes, we offer 24/7 technical support via email and chat for all customers.',
},
{
question: 'Do you ship internationally?',
answer: 'Yes, we ship all over the world. Shipping costs will apply, and will be added at checkout.',
},
]
return (
>
)
}
```
## Tailwind CSS Plugin Integration
State-based utility variants for styling Headless UI components
```jsx
import { Menu } from '@headlessui/react'
function StyledMenu() {
return (
)
}
// Custom prefix configuration
// tailwind.config.js
module.exports = {
plugins: [
require('@headlessui/tailwindcss')({ prefix: 'ui' })
]
}
// Available variants:
// ui-open / ui-not-open
// ui-checked / ui-not-checked
// ui-selected / ui-not-selected
// ui-active / ui-not-active
// ui-disabled / ui-not-disabled
// ui-focus-visible / ui-not-focus-visible
function AllVariantsExample() {
return (
<>
{/* Listbox with state variants */}
▼
Option A
{/* Switch with checked variants */}
Toggle
>
)
}
```
## Summary
Headless UI provides a comprehensive suite of accessible, unstyled UI components that handle the complex logic of interactive interfaces while giving developers complete styling freedom. The library excels at solving common challenges in modern web applications including keyboard navigation, focus management, screen reader support, and state synchronization. Each component follows WAI-ARIA design patterns and best practices, ensuring that applications built with Headless UI are accessible by default without requiring deep accessibility expertise from developers. The v2.2.9 release includes enhanced form components like Button, Checkbox, Input, Select, and Textarea that integrate seamlessly with native HTML forms while providing rich state management and accessibility features.
The component API is consistent across the library, using render props to expose internal state for conditional styling, supporting both controlled and uncontrolled modes for flexibility, and integrating seamlessly with HTML forms for data submission. The Tailwind CSS plugin extends this integration by providing utility variants that respond to component state, enabling declarative styling patterns that keep component logic and visual presentation clearly separated. Whether building dropdown menus, modal dialogs, autocomplete inputs, tabbed interfaces, or accessible forms, Headless UI provides the foundation for creating polished, accessible user experiences with minimal complexity and maximum control. The library's focus on providing functionality without styling constraints makes it particularly well-suited for design systems and component libraries that require precise visual control.