Select
A light wrapper around the native select element that handles tedious accessibility concerns and provides more opinionated states for things like hover and focus.
To get started, install Headless UI via npm:
npm install @headlessui/react
Select controls are built using the Select
component:
import { Select } from '@headlessui/react'
function Example() {
return (
<Select name="status" aria-label="Project status">
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>
)
}
You can pass any props to a Select
that you'd normally pass to the native select
element.
Headless UI keeps track of a lot of state about each component, like whether or not a select is focused, whether a popover is open or closed, or which item in a menu is currently focused via the keyboard.
But because the components are headless and completely unstyled out of the box, you can't see this information in your UI until you provide the styles you want for each state yourself.
The easiest way to style the different states of a Headless UI component is using the data-*
attributes that each
component exposes.
For example, the Select
component exposes a data-focus
attribute, which tells you if the select is currently focused
via keyboard, and a data-hover
attribute, which tells you if the select is currently being hovered by the mouse.
<!-- Rendered `Select` -->
<select name="status" data-focus data-hover>
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</select>
Use the CSS attribute selector to conditionally apply styles based on the presence of these data attributes. If you're using Tailwind CSS, the data attribute modifier makes this easy:
import { Select } from '@headlessui/react'
function Example() {
return (
<Select name="status" className="border data-[hover]:shadow data-[focus]:bg-blue-100" aria-label="Project status"> <option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>
)
}
See the component API for a list of all the available data attributes.
Each component also exposes information about its current state via render props that you can use to conditionally apply different styles or render different content.
For example, the Select
component exposes a focus
state, which tells you if the select is currently focused via the
keyboard, and a hover
state, which tells you if the select is currently being hovered by the mouse.
import { Select } from '@headlessui/react'
import clsx from 'clsx'
import { Fragment } from 'react'
function Example() {
return (
<Select name="status" as={Fragment}>
{({ focus, hover }) => ( <select className={clsx('border', focus && 'bg-blue-100', hover && 'shadow')} aria-label="Project status"> <option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</select>
)} </Select>
)
}
See the component API for a list of all the available render props.
Wrap a Label
and Select
with the Field
component to automatically associate them using a generated ID:
import { Field, Label, Select } from '@headlessui/react'
function Example() {
return (
<Field> <Label>Project status</Label> <Select name="status">
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>
</Field> )
}
Use the Description
component within a Field
to automatically associate it with a Select
using the
aria-describedby
attribute:
import { Description, Field, Label, Select } from '@headlessui/react'
function Example() {
return (
<Field> <Label>Project status</Label>
<Description>This will be visible to clients on the project.</Description> <Select name="status">
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>
</Field> )
}
Add the disabled
prop to the Field
component to disable a Select
and its associated Label
and Description
:
import { Description, Field, Label, Select } from '@headlessui/react'
function Example() {
return (
<Field disabled> <Label className="data-[disabled]:opacity-50">Project status</Label> <Description className="data-[disabled]:opacity-50">This will be visible to clients on the project.</Description> <Select name="status" className="data-[disabled]:bg-gray-100"> <option value="active">Active</option>
<option value="paused">Paused</option>
<option value="delayed">Delayed</option>
<option value="canceled">Canceled</option>
</Select>
</Field>
)
}
You can also disable a select outside of a Field
by adding the disabled prop directly to the Select
itself.
A thin wrapper around the native select
element.
Prop | Default | Description |
as | select | String | Component The element or component the select should render as. |
invalid | false | Boolean Whether or not the select is invalid. |
disabled | false | Boolean Whether or not the select is disabled. |
autoFocus | false | Boolean Whether or not the select should receive focus when first rendered. |
Data Attribute | Render Prop | Description |
data-invalid | invalid |
Whether or not the select is invalid. |
data-disabled | disabled |
Whether or not the select is disabled. |
data-focus | focus |
Whether or not the select is focused. |
data-hover | hover |
Whether or not the select is hovered. |
data-active | active |
Whether or not the select is in an active or pressed state. |
data-autofocus | autofocus |
Whether or not the |
Groups a Label
, Description
, and form control together.
Prop | Default | Description |
as | div | String | Component The element or component the field should render as. |
disabled | false | Boolean Whether or not the field is disabled. |
Data Attribute | Render Prop | Description |
data-disabled | disabled |
Whether or not the field is disabled. |
The Label
component labels a form control.
Prop | Default | Description |
as | label | String | Component The element or component the label should render as. |
passive | false | Boolean When true, clicking the label won't focus the associated form control. |
Data Attribute | Render Prop | Description |
data-disabled | disabled |
Whether or not the parent |
The Description
component describes a form control.
Prop | Default | Description |
as | p | String | Component The element or component the description should render as. |
Data Attribute | Render Prop | Description |
data-disabled | disabled |
Whether or not the parent |
If you're interested in predesigned Tailwind CSS select menu examples, check out Tailwind UI — a collection of beautifully designed and expertly crafted components built by us.
It's a great way to support our work on open-source projects like this and makes it possible for us to improve them and keep them well-maintained.