Select
Displays a list of options for the user to pick from.
You can explore the select component in the following curated examples.
Async Select
Render a Select that fetches items asynchronously.
Select Tabs
Render a Tabs component within a Select.
Virtualized Select
Render a Select that virtualizes its options.
Anatomy
<Select.Root>
<Select.Label />
<Select.Control>
<Select.Trigger>
<Select.ValueText />
</Select.Trigger>
<Select.ClearTrigger />
<Select.Indicator />
</Select.Control>
<Select.Positioner>
<Select.Content>
<Select.ItemGroup>
<Select.ItemGroupLabel />
<Select.Item>
<Select.ItemText />
<Select.ItemIndicator />
</Select.Item>
</Select.ItemGroup>
</Select.Content>
</Select.Positioner>
<Select.HiddenSelect />
</Select.Root>
Examples
Controlled
Use the value and onValueChange props to control the selected items.
Root Provider
An alternative way to control the select is to use the RootProvider component and the useSelect hook. This way you
can access the state and methods from outside the component.
Multiple
To enable multiple item selection:
Grouping
Grouping related options can be useful for organizing options into categories.
- Use the
groupByprop to configure the grouping of the items. - Use the
collection.group()method to get the grouped items. - Use the
Select.ItemGroupandSelect.ItemGroupLabelcomponents to render the grouped items.
Field
Use Field to manage form state, ARIA labels, helper text, and error text.
Form Usage
Here's an example of integrating the Select component with a form library.
Async Loading
Here's an example of how to load the items asynchronously when the select is opened.
Lazy Mount
Use lazyMount and unmountOnExit to control when content is mounted, improving performance.
Select on Highlight
Here's an example of automatically selecting items when they are highlighted (hovered or navigated to with keyboard).
Max Selection
Here's an example of limiting the number of items that can be selected in a multiple select.
Select All
Use selectAll() from the select context to select all items at once.
Overflow
For selects with many items, use positioning.fitViewport to ensure the dropdown fits within the viewport. Combine with
a max-height on the content to enable scrolling.
Guides
Type Safety
The Select.RootComponent type enables you to create typed wrapper components that maintain full type safety for
collection items.
const Select: ArkSelect.RootComponent = (props) => {
return <ArkSelect.Root {...props}>{/* ... */}</ArkSelect.Root>
}
Use the wrapper with full type inference on onValueChange and other callbacks:
const App = () => {
const collection = createListCollection({
initialItems: [
{ label: 'React', value: 'react' },
{ label: 'Vue', value: 'vue' },
],
})
return (
<Select
collection={collection}
onValueChange={(e) => {
// e.items is typed as Array<{ label: string, value: string }>
console.log(e.items)
}}
>
{/* ... */}
</Select>
)
}
Nested Usage
When using the Select component within a Popover or Dialog, avoid rendering its content within a Portal or
Teleport.
This ensures the Select's content stays within the Popover/Dialog's DOM hierarchy rather than being portalled to the document body, maintaining proper interaction and accessibility behavior.
Hidden Select
The Select.HiddenSelect component renders a native HTML <select> element that's visually hidden but remains in the
DOM. This component is essential for:
- Form submission: Native form submission and serialization work seamlessly since the actual
<select>element exists in the DOM - Browser auto-fill: Browsers can properly auto-fill the select based on previously submitted form data
- Progressive enhancement: Forms remain functional even if JavaScript fails to load
<Select.Root>
<Select.HiddenSelect />
{/* Other Select components */}
</Select.Root>
The hidden select automatically syncs with the Select component's value, ensuring form data is always up-to-date.
Empty State
You can create an empty state component that displays when there are no items in the collection. Use the
useSelectContext hook to check the collection size:
const SelectEmpty = (props: React.ComponentProps<'div'>) => {
const select = useSelectContext()
if (select.collection.size === 0) {
return <div {...props} role="presentation" />
}
return null
}
Then use it within your Select content:
<Select.Content>
<SelectEmpty>No items to display</SelectEmpty>
{/* Your items */}
</Select.Content>
Available Size
The following css variables are exposed to the Select.Positioner which you can use to style the Select.Content
/* width of the select trigger */
--reference-width: <pixel-value>;
/* width of the available viewport */
--available-width: <pixel-value>;
/* height of the available viewport */
--available-height: <pixel-value>;
For example, if you want to make sure the maximum height doesn't exceed the available height, you can use the following:
[data-scope='select'][data-part='content'] {
max-height: calc(var(--available-height) - 100px);
}
API Reference
Props
Root
| Prop | Default | Type |
|---|---|---|
collection | ListCollection<T>The collection of items | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
closeOnSelect | true | booleanWhether the select should close after an item is selected |
composite | true | booleanWhether the select is a composed with other composite widgets like tabs or combobox |
defaultHighlightedValue | stringThe initial value of the highlighted item when opened. Use when you don't need to control the highlighted value of the select. | |
defaultOpen | booleanWhether the select's open state is controlled by the user | |
defaultValue | string[]The initial default value of the select when rendered. Use when you don't need to control the value of the select. | |
deselectable | booleanWhether the value can be cleared by clicking the selected item. **Note:** this is only applicable for single selection | |
disabled | booleanWhether the select is disabled | |
form | stringThe associate form of the underlying select. | |
highlightedValue | stringThe controlled key of the highlighted item | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
root: string
content: string
control: string
trigger: string
clearTrigger: string
label: string
hiddenSelect: string
positioner: string
item: (id: string | number) => string
itemGroup: (id: string | number) => string
itemGroupLabel: (id: string | number) => string
}>The ids of the elements in the select. Useful for composition. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
invalid | booleanWhether the select is invalid | |
lazyMount | false | booleanWhether to enable lazy mounting |
loopFocus | false | booleanWhether to loop the keyboard navigation through the options |
multiple | booleanWhether to allow multiple selection | |
name | stringThe `name` attribute of the underlying select. | |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onHighlightChange | (details: HighlightChangeDetails<T>) => voidThe callback fired when the highlighted item changes. | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => voidFunction called when the popup is opened | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onSelect | (details: SelectionDetails) => voidFunction called when an item is selected | |
onValueChange | (details: ValueChangeDetails<T>) => voidThe callback fired when the selected item changes. | |
open | booleanWhether the select menu is open | |
positioning | PositioningOptionsThe positioning options of the menu. | |
present | booleanWhether the node is present (controlled by the user) | |
readOnly | booleanWhether the select is read-only | |
required | booleanWhether the select is required | |
scrollToIndexFn | (details: ScrollToIndexDetails) => voidFunction to scroll to a specific index | |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
unmountOnExit | false | booleanWhether to unmount on exit. |
value | string[]The controlled keys of the selected items |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | root |
[data-invalid] | Present when invalid |
[data-readonly] | Present when read-only |
ClearTrigger
Renders a <button> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | clear-trigger |
[data-invalid] | Present when invalid |
Content
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | content |
[data-state] | "open" | "closed" |
[data-nested] | listbox |
[data-has-nested] | listbox |
[data-placement] | The placement of the content |
[data-activedescendant] | The id the active descendant of the content |
| CSS Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
--nested-layer-count | The number of nested selects |
Control
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | control |
[data-state] | "open" | "closed" |
[data-focus] | Present when focused |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
HiddenSelect
Renders a <select> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Indicator
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | indicator |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-readonly] | Present when read-only |
ItemGroupLabel
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
ItemGroup
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | item-group |
[data-disabled] | Present when disabled |
ItemIndicator
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | item-indicator |
[data-state] | "checked" | "unchecked" |
Item
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
item | anyThe item to render | |
persistFocus | booleanWhether hovering outside should clear the highlighted state |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | item |
[data-value] | The value of the item |
[data-state] | "checked" | "unchecked" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
ItemText
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | item-text |
[data-state] | "checked" | "unchecked" |
[data-disabled] | Present when disabled |
[data-highlighted] | Present when highlighted |
Label
Renders a <label> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | label |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-readonly] | Present when read-only |
[data-required] | Present when required |
List
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Positioner
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| CSS Variable | Description |
|---|---|
--reference-width | The width of the reference element |
--reference-height | The height of the root |
--available-width | The available width in viewport |
--available-height | The available height in viewport |
--x | The x position for transform |
--y | The y position for transform |
--z-index | The z-index value |
--transform-origin | The transform origin for animations |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UseSelectReturn<T> | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
lazyMount | false | booleanWhether to enable lazy mounting |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
present | booleanWhether the node is present (controlled by the user) | |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
unmountOnExit | false | booleanWhether to unmount on exit. |
Trigger
Renders a <button> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | trigger |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-readonly] | Present when read-only |
[data-placement] | The placement of the trigger |
[data-placeholder-shown] | Present when placeholder is shown |
ValueText
Renders a <span> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
placeholder | stringText to display when no value is selected. |
| Attribute | Description |
|---|---|
[data-scope] | select |
[data-part] | value-text |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-focus] | Present when focused |
Context
API
| Property | Type |
|---|---|
focused | booleanWhether the select is focused |
open | booleanWhether the select is open |
empty | booleanWhether the select value is empty |
highlightedValue | stringThe value of the highlighted item |
highlightedItem | VThe highlighted item |
setHighlightValue | (value: string) => voidFunction to highlight a value |
clearHighlightValue | VoidFunctionFunction to clear the highlighted value |
selectedItems | V[]The selected items |
hasSelectedItems | booleanWhether there's a selected option |
value | string[]The selected item keys |
valueAsString | stringThe string representation of the selected items |
selectValue | (value: string) => voidFunction to select a value |
selectAll | VoidFunctionFunction to select all values |
setValue | (value: string[]) => voidFunction to set the value of the select |
clearValue | (value?: string) => voidFunction to clear the value of the select. If a value is provided, it will only clear that value, otherwise, it will clear all values. |
focus | VoidFunctionFunction to focus on the select input |
getItemState | (props: ItemProps<any>) => ItemStateReturns the state of a select item |
setOpen | (open: boolean) => voidFunction to open or close the select |
collection | ListCollection<V>Function to toggle the select |
reposition | (options?: Partial<PositioningOptions>) => voidFunction to set the positioning options of the select |
multiple | booleanWhether the select allows multiple selections |
disabled | booleanWhether the select is disabled |
Accessibility
Complies with the Listbox WAI-ARIA design pattern.
Keyboard Support
| Key | Description |
|---|---|
Space | When focus is on trigger, opens the select and focuses the first selected item. When focus is on the content, selects the highlighted item. |
Enter | When focus is on trigger, opens the select and focuses the first selected item. When focus is on content, selects the focused item. |
ArrowDown | When focus is on trigger, opens the select. When focus is on content, moves focus to the next item. |
ArrowUp | When focus is on trigger, opens the select. When focus is on content, moves focus to the previous item. |
Esc | Closes the select and moves focus to trigger. |
A-Za-z | When focus is on trigger, selects the item whose label starts with the typed character. When focus is on the listbox, moves focus to the next item with a label that starts with the typed character. |