Select
A field that lets users choose one or several options from a list that opens in a popup.
A select lets users choose one option from a list that opens in a popup, or several with multiple. The trigger shows the selected option, or a placeholder while none is selected, and a press on it opens the list. By default, the popup opens over the trigger, so that the selected option lines up with the text in the trigger. items on Select gives the select the label of each value, so the trigger shows the label of the selected option instead of its raw value. SelectGroup provides the padding around the options, so the options sit in a SelectGroup even when the list has a single group. The trigger is as wide as its content, and the popup takes the width of the trigger but is at least 9rem wide. The trigger has no visible label of its own, so the examples name it with aria-label.
Usage
Examples
With Groups
Long lists often combine options of different kinds, for example product categories from several departments. Related options sit together in a SelectGroup, and a SelectLabel names each group, so users find an option faster and assistive technology reads the name of its group as well.
With Separator
Labels alone may not keep groups apart clearly enough, especially in a long list that users scan quickly. Placed between two groups, SelectSeparator marks where one set of options ends and the next begins, so users recognize the change of kind without reading every label.
With Icon
In a dense form, users should recognize what a field asks for before they read its value. An icon in the trigger gives that hint at a glance and stays in place whichever option users select.
Small
Toolbars, filter bars and table headers leave little room for a field. With size set to "sm" on SelectTrigger, the select claims less space and fits into such a row without outweighing the content it filters.
Default Size
Forms, dialogs and settings pages give a field the room it needs. There the trigger keeps the size "default", which applies whenever no other size is set, so a select lines up with the inputs around it.
Scrollable
Certain choices span more options than the screen can show at once, such as every supplier in an assortment. The list then stays within the available space and scrolls. Wherever further options lie beyond the visible ones, a button at that end scrolls on while the pointer rests on it, and users can also type the first characters of an option to move straight to it.
Multiple
Reports and filters often cover more than one option at a time, such as several regions in a sales comparison. Through multiple, users select as many options as they need, the popup stays open between their choices, and another press on a selected option removes it again.
Without Item Alignment
Opening over the trigger keeps the selected option where users were looking, yet it covers the field itself. With alignItemWithTrigger set to false on SelectContent, the popup opens beside the trigger instead, below it unless side says otherwise, so the field and its surroundings stay in view while users choose.
Top Side
At the bottom of a panel or in a footer bar, the room for a list lies above the select. Set to "top", side opens the popup there once alignItemWithTrigger is false, because a popup that lies over the trigger ignores the side.
Right Side
Along the left edge of a screen, in a sidebar for instance, the open space lies to the right of the select. Together with alignItemWithTrigger set to false, side set to "right" lets the list unfold into that space instead of covering what lies below the trigger.
Left Side
Panels on the right edge of a screen, such as a details pane, leave their room to the left. Once alignItemWithTrigger is false, side set to "left" opens the popup on that side, while the values "inline-start" and "inline-end" follow the reading direction for products in right-to-left languages.
Default Value
Many forms begin with a choice that most users keep, such as the current week in a sales report. Through defaultValue the select starts with that option selected, and users change it only when they need another one.
Controlled Value
Other parts of the interface often depend on the selection, such as a dashboard that filters its figures by the chosen category. The application then holds the value through value and onValueChange, so it can reset or change the selection from elsewhere while the select always shows the current choice.
Controlled Open State
Another part of the interface may need to open the list, for example a keyboard shortcut or a guided step that points users to a missing choice. Through open and onOpenChange, the application holds whether the popup is open, while users still open and close it as usual.
Disabled
Until an earlier choice is made, a select may have nothing meaningful to offer, such as sizes before a product is chosen. Marked as disabled, it neither opens nor changes its value, keyboard focus passes over it, and the form leaves its value out.
Disabled Item
Single options are sometimes unavailable for a while, such as a promotion that has not started yet. With disabled on its SelectItem, the option remains in the list, so users still see the full range, but they cannot select it.
Read-Only
Some values are decided elsewhere, by head office or by an automated process, yet users still need to know them. Through readOnly, users open the list and read every option without changing the selection, and the form still submits the value.
Invalid
A required choice that is missing, or one that no longer fits the rest of a form, should stand out before users submit. With aria-invalid on SelectTrigger, the field signals the error and assistive technology announces it, so users find the field that needs their attention.
API Reference
Select
| Prop | items |
|---|---|
| Type | Record<string, ReactNode> | ReadonlyArray<{ label: ReactNode; value: any }> | ReadonlyArray<Group<any>> |
| Default | – |
| Description | Gives the select the label of each value, so that SelectValue shows the label of the selected option instead of its raw value. It takes an object that maps each value to its label, an array of objects with label and value, or an array of groups that each hold such objects in items. It doesn't render the options: each one still needs a SelectItem. |
| Prop | value |
|---|---|
| Type | Value | Value[] | null |
| Default | – |
| Description | Sets the selected value and makes the select controlled. Update it in onValueChange. With multiple, it is an array of values. |
| Prop | defaultValue |
|---|---|
| Type | Value | Value[] | null |
| Default | – |
| Description | Sets the value that is selected at first render. The select then tracks the selection itself. With multiple, it is an array of values. |
| Prop | onValueChange |
|---|---|
| Type | (value: Value | Value[] | null, eventDetails: SelectRootChangeEventDetails) => void |
| Default | – |
| Description | Runs when users select an option, and with multiple also when they deselect one. It receives the value that follows: the value of the option, or with multiple the array of selected values. When the selected option is removed from the list, a select with a single value returns to the value of the first render, or to null if that option is gone as well. |
| Prop | multiple |
|---|---|
| Type | boolean |
| Default | false |
| Description | Lets users select several options. The value is then an array, a press on a selected option removes it from the selection, and the popup stays open after each press. |
| Prop | open |
|---|---|
| Type | boolean |
| Default | – |
| Description | Sets whether the popup is open and makes the open state controlled. Update it in onOpenChange. |
| Prop | defaultOpen |
|---|---|
| Type | boolean |
| Default | false |
| Description | Opens the popup at first render. The select then tracks its open state itself. |
| Prop | onOpenChange |
|---|---|
| Type | (open: boolean, eventDetails: SelectRootChangeEventDetails) => void |
| Default | – |
| Description | Runs when users open or close the popup. It receives the open state that follows. |
| Prop | onOpenChangeComplete |
|---|---|
| Type | (open: boolean) => void |
| Default | – |
| Description | Runs after the popup has opened or closed and its animations have finished. |
| Prop | modal |
|---|---|
| Type | boolean |
| Default | true |
| Description | Locks the page while the popup is open: the page doesn't scroll, and elements outside of the select don't react to the pointer. With false, elements outside of the select react to the pointer. The page still doesn't scroll while the popup lies over the trigger, which alignItemWithTrigger of SelectContent decides. When a touch opened a modal select, the page still scrolls unless the popup is about as wide as the viewport. |
| Prop | highlightItemOnHover |
|---|---|
| Type | boolean |
| Default | true |
| Description | Moves the highlight to the option under the pointer. With false, only the keyboard moves the highlight. |
| Prop | itemToStringLabel |
|---|---|
| Type | (itemValue: Value) => string |
| Default | – |
| Description | Converts a value that is an object to the text that the trigger shows. An object with the properties value and label doesn't need it, because the select reads label itself. |
| Prop | itemToStringValue |
|---|---|
| Type | (itemValue: Value) => string |
| Default | – |
| Description | Converts a value that is an object to the text that the form submits. An object with the properties value and label doesn't need it, because the select reads value itself. |
| Prop | isItemEqualToValue |
|---|---|
| Type | (itemValue: Value, value: Value) => boolean |
| Default | – |
| Description | Decides whether the value of an option equals the selected value. Set it when values are objects that aren't the same instances as the selected value. Without it, the select compares with Object.is. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the popup and changing the value, and leaves the value out of the submitted form. It disables the trigger and every option. |
| Prop | readOnly |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from changing the value. The popup still opens, so users can read the options, and the value is submitted with the form. |
| Prop | required |
|---|---|
| Type | boolean |
| Default | false |
| Description | Requires users to select an option before they can submit the form. |
| Prop | name |
|---|---|
| Type | string |
| Default | – |
| Description | Identifies the select when the form is submitted. With multiple, the form submits one entry with this name for each selected value. |
| Prop | form |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the ID of the form that the select belongs to. Set it when the select is rendered outside of that form. |
| Prop | autoComplete |
|---|---|
| Type | string |
| Default | – |
| Description | Gives the browser a hint for autofill, as the HTML attribute autocomplete does. |
| Prop | id |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the ID of the trigger, so that a label can refer to the select with htmlFor. |
| Prop | inputRef |
|---|---|
| Type | Ref<HTMLInputElement> |
| Default | – |
| Description | Receives the hidden input element that carries the value of the select in a form. |
| Prop | actionsRef |
|---|---|
| Type | RefObject<SelectRootActions | null> |
| Default | – |
| Description | Receives the function unmount, which removes the popup from the DOM after a closing animation that the code controls itself. |
SelectTrigger
| Prop | size |
|---|---|
| Type | "sm" | "default" |
| Default | "default" |
| Description | Sets the height of the trigger: 2rem for "default" and 1.75rem for "sm". "sm" also reduces the corner radius. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from opening the popup with this trigger. A disabled select disables the trigger as well. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the trigger with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | true |
| Description | Declares whether the rendered element is a native button. Set it to false when render returns a different element. |
SelectValue
| Prop | placeholder |
|---|---|
| Type | ReactNode |
| Default | – |
| Description | Sets the content that the part shows while no option is selected. children takes precedence over it, and so does the label that items gives to the value null. |
| Prop | children |
|---|---|
| Type | ReactNode | ((value: any) => ReactNode) |
| Default | – |
| Description | Replaces the label of the selected option, which the part shows without it. A function receives the selected value, or with multiple the array of selected values, and returns the content. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the value with another component. |
SelectContent
| Prop | alignItemWithTrigger |
|---|---|
| Type | boolean |
| Default | true |
| Description | Opens the popup over the trigger, so that the selected option lines up with the text in the trigger. While it applies, side, sideOffset, align and alignOffset have no effect. It doesn't apply when a touch opened the select, and it gives way to the side of the trigger when the viewport leaves too little space around the trigger. With false, the popup always opens on a side of the trigger. |
| Prop | side |
|---|---|
| Type | "top" | "bottom" | "left" | "right" | "inline-end" | "inline-start" |
| Default | "bottom" |
| Description | Sets the side of the trigger that the popup opens on. "inline-start" and "inline-end" follow the reading direction. The popup moves to the opposite side when the chosen one has too little space. |
| Prop | sideOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | 4 |
| Description | Sets the distance between the trigger and the popup in pixels. A function receives the side, the alignment and the dimensions of the trigger and the popup, and returns the distance. |
| Prop | align |
|---|---|
| Type | "start" | "center" | "end" |
| Default | "center" |
| Description | Sets where the popup lines up with the trigger along the chosen side: at its start, its center or its end. |
| Prop | alignOffset |
|---|---|
| Type | number | OffsetFunction |
| Default | 0 |
| Description | Moves the popup along the alignment axis by a number of pixels. A function receives the same data as the one for sideOffset and returns the offset. |
| Prop | finalFocus |
|---|---|
| Type | boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void) |
| Default | – |
| Description | Determines the element that receives focus when the select closes. Without it, focus returns to the trigger or to the element that had focus before. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the content with another component. |
SelectGroup
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the group with another component. |
SelectLabel
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the label with another component. |
SelectItem
| Prop | value |
|---|---|
| Type | any |
| Default | null |
| Description | Identifies the option. value, defaultValue and onValueChange of the select work with it. |
| Prop | disabled |
|---|---|
| Type | boolean |
| Default | false |
| Description | Prevents users from selecting the option. |
| Prop | label |
|---|---|
| Type | string |
| Default | – |
| Description | Sets the text that the select matches when users type to move to an option. Without it, the select matches the text content of the option. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the item with another component. |
| Prop | nativeButton |
|---|---|
| Type | boolean |
| Default | false |
| Description | Declares whether the rendered element is a native button. Set it to true when render returns a button. |
SelectSeparator
| Prop | orientation |
|---|---|
| Type | "horizontal" | "vertical" |
| Default | "horizontal" |
| Description | Sets the data-orientation attribute of the separator. The separator draws a horizontal line with either value. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the separator with another component. |
SelectScrollUpButton
| Prop | keepMounted |
|---|---|
| Type | boolean |
| Default | false |
| Description | Keeps the button in the DOM while the list can't scroll up. Without it, the select renders the button only while options lie above the visible ones. SelectContent renders this button itself at the top of the list. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the button with another component. |
SelectScrollDownButton
| Prop | keepMounted |
|---|---|
| Type | boolean |
| Default | false |
| Description | Keeps the button in the DOM while the list can't scroll down. Without it, the select renders the button only while options lie below the visible ones. SelectContent renders this button itself at the bottom of the list. |
| Prop | render |
|---|---|
| Type | ReactElement | render function |
| Default | – |
| Description | Replaces the native element or composes the button with another component. |