# Select Displays a list of options for the user to pick from — triggered by a button. ## Import ``` Copyts import { Select } from "@kobalte/core/select"; // or import { Root, Label, ... } from "@kobalte/core/select"; // or (deprecated) import { Select } from "@kobalte/core"; ``` ``` Copyts import { Select } from "@kobalte/core/select"; // or import { Root, Label, ... } from "@kobalte/core/select"; // or (deprecated) import { Select } from "@kobalte/core"; ``` ## Features - Exposed to assistive technology as a button with a listbox popup using the [WAI ARIA Listbox](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) design pattern. - Support for single and multiple selection. - Support for disabled options. - Labeling support for accessibility. - Support for description and error message help text linked to the button via ARIA. - Tab stop focus management. - Keyboard support for opening the listbox using the arrow keys, including automatically focusing the first or last item accordingly. - Typeahead to allow selecting options by typing text, even without opening the listbox. - Browser autofill integration via a hidden native ` ``` ``` Copytsx ``` ## Example Select a fruit…Sort index.tsxstyle.css ``` Copytsx import { Select } from "@kobalte/core/select"; import { CaretSortIcon, CheckIcon } from "some-icon-library"; import "./style.css"; function App() { return ( ); } ``` ``` Copytsx import { Select } from "@kobalte/core/select"; import { CaretSortIcon, CheckIcon } from "some-icon-library"; import "./style.css"; function App() { return ( ); } ``` ## Usage ### Default value An initial, uncontrolled value can be provided using the `defaultValue` prop, which accepts a value corresponding with the `options`. BlueberrySort ``` Copytsx ``` ``` Copytsx ``` ### Controlled value The `value` prop, which accepts a value corresponding with the `options` prop, can be used to make the value controlled. The `onChange` event is fired when the user selects an option, and receives the selected option. BlueberrySort Your favorite fruit is: Blueberry. ``` Copytsx import { createSignal } from "solid-js"; export function ControlledExample() { const [value, setValue] = createSignal("Blueberry"); return ( <>

Your favorite fruit is: {value()}.

); } ``` ``` Copytsx import { createSignal } from "solid-js"; export function ControlledExample() { const [value, setValue] = createSignal("Blueberry"); return ( <>

Your favorite fruit is: {value()}.

); } ``` ### Description The `Select.Description` component can be used to associate additional help text with a select. Select a fruit…Sort Choose the fruit you like the most. ``` Copytsx ``` ``` Copytsx ``` ### Error message The `Select.ErrorMessage` component can be used to help the user fix a validation error. It should be combined with the `validationState` prop to semantically mark the select as invalid for assistive technologies. By default, it will render only when the `validationState` prop is set to `invalid`, use the `forceMount` prop to always render the error message (ex: for usage with animation libraries). GrapesSort Hmm, I prefer apples. ``` Copytsx import { createSignal } from "solid-js"; export function ErrorMessageExample() { const [value, setValue] = createSignal("Grapes"); return ( ); } ``` ``` Copytsx import { createSignal } from "solid-js"; export function ErrorMessageExample() { const [value, setValue] = createSignal("Grapes"); return ( ); } ``` ### HTML forms The select `name` prop, paired with the `Select.HiddenSelect` component, can be used for integration with HTML forms. AppleBananaBlueberryGrapesPineapple Select a fruit…Sort ResetSubmit ``` Copytsx function HTMLFormExample() { const onSubmit = (e: SubmitEvent) => { // handle form submission. }; return (
); } ``` ``` Copytsx function HTMLFormExample() { const onSubmit = (e: SubmitEvent) => { // handle form submission. }; return (
); } ``` ### Using object as options Objects can be used as options instead of plain strings. In this case you have to tell the select how it should work with the provided options. For this you **have to use** the following props : - `optionValue`: The property name to use as the value of an option (submitted with `
`). - `optionTextValue`: The property name to use as the text value of an option for keyboard navigation. - `optionDisabled`: The property name to use as the disabled flag of an option. Select a food…Sort ``` Copytsx interface Fruit { value: string; label: string; disabled: boolean; } const options: Fruit[] = [\ { value: "apple", label: "Apple", disabled: false },\ { value: "banana", label: "Banana", disabled: false },\ { value: "blueberry", label: "Blueberry", disabled: false },\ { value: "grapes", label: "Grapes", disabled: true },\ { value: "pineapple", label: "Pineapple", disabled: false },\ ]; function ObjectExample() { return ( ); } ``` ``` Copytsx interface Fruit { value: string; label: string; disabled: boolean; } const options: Fruit[] = [\ { value: "apple", label: "Apple", disabled: false },\ { value: "banana", label: "Banana", disabled: false },\ { value: "blueberry", label: "Blueberry", disabled: false },\ { value: "grapes", label: "Grapes", disabled: true },\ { value: "pineapple", label: "Pineapple", disabled: false },\ ]; function ObjectExample() { return ( ); } ``` ### Using option groups When using option groups you have to tell the select how to distinguish an option from a group. For this you **have to use** the following props : - `optionGroupChildren`: The property name that refers to the children options of an option group. Additionally, the `sectionComponent` prop is used to display the option group label in the select. Select a food…Sort ``` Copytsx interface Food { value: string; label: string; disabled: boolean; } interface Category { label: string; options: Food[]; } const options: Category[] = [\ {\ label: "Fruits",\ options: [\ { value: "apple", label: "Apple", disabled: false },\ { value: "banana", label: "Banana", disabled: false },\ { value: "blueberry", label: "Blueberry", disabled: false },\ { value: "grapes", label: "Grapes", disabled: true },\ { value: "pineapple", label: "Pineapple", disabled: false },\ ],\ },\ {\ label: "Meat",\ options: [\ { value: "beef", label: "Beef", disabled: false },\ { value: "chicken", label: "Chicken", disabled: false },\ { value: "lamb", label: "Lamb", disabled: false },\ { value: "pork", label: "Pork", disabled: false },\ ],\ },\ ]; function OptionGroupExample() { return ( options={options} optionValue="value" optionTextValue="label" optionDisabled="disabled" optionGroupChildren="options" placeholder="Select a food…" itemComponent={props => ( {props.item.rawValue.label} )} sectionComponent={props => {props.section.rawValue.label}} > >{state => state.selectedOption().label} ); } ``` ``` Copytsx interface Food { value: string; label: string; disabled: boolean; } interface Category { label: string; options: Food[]; } const options: Category[] = [\ {\ label: "Fruits",\ options: [\ { value: "apple", label: "Apple", disabled: false },\ { value: "banana", label: "Banana", disabled: false },\ { value: "blueberry", label: "Blueberry", disabled: false },\ { value: "grapes", label: "Grapes", disabled: true },\ { value: "pineapple", label: "Pineapple", disabled: false },\ ],\ },\ {\ label: "Meat",\ options: [\ { value: "beef", label: "Beef", disabled: false },\ { value: "chicken", label: "Chicken", disabled: false },\ { value: "lamb", label: "Lamb", disabled: false },\ { value: "pork", label: "Pork", disabled: false },\ ],\ },\ ]; function OptionGroupExample() { return ( options={options} optionValue="value" optionTextValue="label" optionDisabled="disabled" optionGroupChildren="options" placeholder="Select a food…" itemComponent={props => ( {props.item.rawValue.label} )} sectionComponent={props => {props.section.rawValue.label}} > >{state => state.selectedOption().label} ); } ``` Notice the usage of generics on `Select` for proper TypeScript support. ### Multiple selection The `multiple` prop can be used to create a select that allow multi-selection. In this case the value provided to `value`, `defaultValue` and `onChange` props is of type `Array`. The `Select.Value` children _render prop_ expose an array of selected options, and two method for removing an option from the selection and clear the selection. Additionally, the example below uses the `as` prop to render a `div` for the `Select.Trigger` since HTML button can't contain interactive elements according to the [W3C](https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element). BlueberryCrossGrapesCross CrossSort Your favorite fruits are: Blueberry, Grapes. ``` Copytsx import { createSignal } from "solid-js"; function MultipleSelectionExample() { const [values, setValues] = createSignal(["Blueberry", "Grapes"]); return ( <> multiple value={values()} onChange={setValues} options={["Apple", "Banana", "Blueberry", "Grapes", "Pineapple"]} placeholder="Select some fruits…" itemComponent={props => ( {props.item.rawValue} )} > > {state => ( <>
{option => ( e.stopPropagation()}> {option} )}
)}

Your favorite fruits are: {values().join(", ")}.

); } ``` ``` Copytsx import { createSignal } from "solid-js"; function MultipleSelectionExample() { const [values, setValues] = createSignal(["Blueberry", "Grapes"]); return ( <> multiple value={values()} onChange={setValues} options={["Apple", "Banana", "Blueberry", "Grapes", "Pineapple"]} placeholder="Select some fruits…" itemComponent={props => ( {props.item.rawValue} )} > > {state => ( <>
{option => ( e.stopPropagation()}> {option} )}
)}

Your favorite fruits are: {values().join(", ")}.

); } ``` ### Virtual scrolling When dealing with large collection of items, it's recommended to use a virtual scrolling solution to improve performance. While Kobalte doesn't provide any built-in virtual scrolling API, it can easily be integrated with a 3rd party library. The example below demonstrate how to virtualize an array of 100,000 options using the [`@tanstack/solid-virtual`](https://tanstack.com/virtual/v3) package. Select an item…Sort ``` Copytsx import { Select } from "@kobalte/core/select"; import { createVirtualizer } from "@tanstack/solid-virtual"; interface Item { value: string; label: string; disabled: boolean; } const options: Item[] = Array.from({ length: 100_000 }, (_, i) => ({ value: `${i}`, label: `Item #${i + 1}`, disabled: false, })); function SelectContent(props: { options: Item[] }) { let listboxRef: HTMLUListElement | undefined; const virtualizer = createVirtualizer({ count: props.options.length, getScrollElement: () => listboxRef, getItemKey: (index: number) => props.options[index].value, estimateSize: () => 32, enableSmoothScroll: false, overscan: 5, }); return ( virtualizer.scrollToIndex(props.options.findIndex(option => option.value === key)) } style={{ height: "200px", width: "100%", overflow: "auto" }} > {items => (
{virtualRow => { const item = items().getItem(virtualRow.key); if (item) { return ( {item.rawValue.label} ); } }}
)}
); } function VirtualizedExample() { return ( ); } ``` ``` Copytsx import { Select } from "@kobalte/core/select"; import { createVirtualizer } from "@tanstack/solid-virtual"; interface Item { value: string; label: string; disabled: boolean; } const options: Item[] = Array.from({ length: 100_000 }, (_, i) => ({ value: `${i}`, label: `Item #${i + 1}`, disabled: false, })); function SelectContent(props: { options: Item[] }) { let listboxRef: HTMLUListElement | undefined; const virtualizer = createVirtualizer({ count: props.options.length, getScrollElement: () => listboxRef, getItemKey: (index: number) => props.options[index].value, estimateSize: () => 32, enableSmoothScroll: false, overscan: 5, }); return ( virtualizer.scrollToIndex(props.options.findIndex(option => option.value === key)) } style={{ height: "200px", width: "100%", overflow: "auto" }} > {items => (
{virtualRow => { const item = items().getItem(virtualRow.key); if (item) { return ( {item.rawValue.label} ); } }}
)}
); } function VirtualizedExample() { return ( ); } ``` ### Origin-aware animations We expose a CSS custom property `--kb-select-content-transform-origin` which can be used to animate the content from its computed origin. ``` Copycss /* style.css */ .select__content { transform-origin: var(--kb-select-content-transform-origin); animation: contentHide 250ms ease-in forwards; } .select__content[data-expanded] { animation: contentShow 250ms ease-out; } @keyframes contentShow { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } } @keyframes contentHide { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-8px); } } ``` ``` Copycss /* style.css */ .select__content { transform-origin: var(--kb-select-content-transform-origin); animation: contentHide 250ms ease-in forwards; } .select__content[data-expanded] { animation: contentShow 250ms ease-out; } @keyframes contentShow { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } } @keyframes contentHide { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-8px); } } ``` ## API Reference ### Select `Select` is equivalent to the `Root` import from `@kobalte/core/select` (and deprecated `Select.Root`). | Prop | Description | | --- | --- | | options | `Array`
An array of options to display as the available options. | | optionValue | `keyof T | ((option: T) => string | number)`
Property name or getter function to use as the value of an option. This is the value that will be submitted when the select is part of a ``. | | optionTextValue | `keyof T | ((option: T) => string)`
Property name or getter function to use as the text value of an option for typeahead purpose. | | optionDisabled | `keyof T | ((option: T) => boolean)`
Property name or getter function to use as the disabled flag of an option. | | optionGroupChildren | `keyof U`
Property name that refers to the children options of an option group. | | itemComponent | `Component>`
When NOT virtualized, the component to render as an item in the `Select.Listbox`. | | sectionComponent | `Component>`
When NOT virtualized, the component to render as a section in the `Select.Listbox`. | | multiple | `boolean`
Whether the select allows multi-selection. | | placeholder | `JSX.Element`
The content that will be rendered when no value or defaultValue is set. | | value | `T | Array`
The controlled value of the select. | | defaultValue | `T | Array`
The value of the select when initially rendered. Useful when you do not need to control the value. | | onChange | `(value: T | Array) => void`
Event handler called when the value changes. | | open | `boolean`
The controlled open state of the select. | | defaultOpen | `boolean`
The default open state when initially rendered. Useful when you do not need to control the open state. | | onOpenChange | `(open: boolean) => void`
Event handler called when the open state of the select changes. | | allowDuplicateSelectionEvents | `boolean`
Whether `onChange` should fire even if the new value is the same as the last. | | disallowEmptySelection | `boolean`
Whether the select allows empty selection or not. | | closeOnSelection | `boolean`
Whether the select closes after selection. | | selectionBehavior | `'toggle' | 'replace'`
How selection should behave in the select. | | virtualized | `boolean`
Whether the select uses virtual scrolling. | | modal | `boolean`
Whether the select should be the only visible content for screen readers, when set to `true`:
\- interaction with outside elements will be disabled.
\- scroll will be locked.
\- focus will be locked inside the select content.
\- elements outside the select content will not be visible for screen readers. | | preventScroll | `boolean`
Whether the scroll should be locked even if the select is not modal. | | forceMount | `boolean`
Used to force mounting the select (portal, positioner and content) when more control is needed. Useful when controlling animation with SolidJS animation libraries. | | name | `string`
The name of the select. Submitted with its owning form as part of a name/value pair. | | validationState | `'valid' | 'invalid'`
Whether the select should display its "valid" or "invalid" visual styling. | | required | `boolean`
Whether the user must select an item before the owning form can be submitted. | | disabled | `boolean`
Whether the select is disabled. | | readOnly | `boolean`
Whether the select items can be selected but not changed by the user. | | autoComplete | `string`
Describes the type of autocomplete functionality the input should provide if any. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete) | `Select` also accepts the following props to customize the placement of the `Select.Content`. | Prop | Description | | --- | --- | | placement | `Placement`
The placement of the select content. | | gutter | `number`
The distance between the select content and the trigger element. | | shift | `number`
The skidding of the select content along the trigger element. | | flip | `boolean | string`
Controls the behavior of the select content when it overflows the viewport:
\- If a `boolean`, specifies whether the select content should flip to the opposite side when it overflows.
\- If a `string`, indicates the preferred fallback placements when it overflows.
The placements must be spaced-delimited, e.g. "top left". | | slide | `boolean`
Whether the select content should slide when it overflows. | | overlap | `boolean`
Whether the select content can overlap the trigger element when it overflows. | | sameWidth | `boolean`
Whether the select content should have the same width as the trigger element. This will be exposed to CSS as `--kb-popper-anchor-width`. | | fitViewport | `boolean`
Whether the select content should fit the viewport. If this is set to true, the select content will have `maxWidth` and `maxHeight` set to the viewport size. This will be exposed to CSS as `--kb-popper-available-width` and `--kb-popper-available-height`. | | hideWhenDetached | `boolean`
Whether to hide the select content when the trigger element becomes occluded. | | detachedPadding | `number`
The minimum padding in order to consider the trigger element occluded. | | arrowPadding | `number`
The minimum padding between the arrow and the select content corner. | | overflowPadding | `number`
The minimum padding between the select content and the viewport edge. This will be exposed to CSS as `--kb-popper-overflow-padding`. | | Data attribute | Description | | --- | --- | | data-valid | Present when the select is valid according to the validation rules. | | data-invalid | Present when the select is invalid according to the validation rules. | | data-required | Present when the user must select an item before the owning form can be submitted. | | data-disabled | Present when the select is disabled. | | data-readonly | Present when the select is read only. | `Select.Label`, `Select.Trigger`, `Select.Value`, `Select.Description` and `Select.ErrorMesssage` shares the same data-attributes. ### Select.Trigger `Select.Trigger` consists of [Button](https://kobalte.dev/docs/core/components/button). | Data attribute | Description | | --- | --- | | data-expanded | Present when the select is open. | | data-closed | Present when the select is close. | ### Select.Value | Render Prop | Description | | --- | --- | | selectedOption | `Accessor`
The first (or only, in case of single select) selected option. | | selectedOptions | `Accessor`
An array of selected options. It will contain only one value in case of single select. | | remove | `(option: T) => void`
A function to remove an option from the selection. | | clear | `() => void`
A function to clear the selection. | | Data attribute | Description | | --- | --- | | data-placeholder-shown | Present when the select placeholder is visible (no value selected). | ### Select.Icon | Data attribute | Description | | --- | --- | | data-expanded | Present when the select is open. | | data-closed | Present when the select is close. | ### Select.ErrorMessage | Prop | Description | | --- | --- | | forceMount | `boolean`
Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries. | ### Select.Content The popper positioner will copy the same `z-index` as the `Select.Content`. | Data attribute | Description | | --- | --- | | data-expanded | Present when the select is open. | | data-closed | Present when the select is close. | ### Select.Arrow | Prop | Description | | --- | --- | | size | `number`
The size of the arrow. | ### Select.Listbox | Prop | Description | | --- | --- | | scrollRef | `Accessor`
The ref attached to the scrollable element, used to provide automatic scrolling on item focus. If not provided, defaults to the listbox. | | scrollToItem | `(key: string) => void`
When virtualized, the Virtualizer function used to scroll to the item of the given key. | | children | `(items: Accessor>>) => JSX.Element`
When virtualized, a map function that receives an _items_ signal representing all items and sections. | ### Select.Item | Prop | Description | | --- | --- | | item | `CollectionNode`
The collection node to render. | | Data attribute | Description | | --- | --- | | data-disabled | Present when the item is disabled. | | data-selected | Present when the item is selected. | | data-highlighted | Present when the item is highlighted. | `Select.ItemLabel`, `Select.ItemDescription` and `Select.ItemIndicator` shares the same data-attributes. ### Select.ItemIndicator | Prop | Description | | --- | --- | | forceMount | `boolean`
Used to force mounting when more control is needed. Useful when controlling animation with SolidJS animation libraries. | ## Rendered elements | Component | Default rendered element | | --- | --- | | `Select` | `div` | | `Select.Label` | `span` | | `Select.Description` | `div` | | `Select.ErrorMessage` | `div` | | `Select.Trigger` | `button` | | `Select.Value` | `span` | | `Select.Icon` | `span` | | `Select.Portal` | `Portal` | | `Select.Content` | `div` | | `Select.Arrow` | `div` | | `Select.Listbox` | `ul` | | `Select.Section` | `li` | | `Select.Item` | `li` | | `Select.ItemLabel` | `div` | | `Select.ItemDescription` | `div` | | `Select.ItemIndicator` | `div` | ## Accessibility ### Keyboard Interactions | Key | Description | | --- | --- | | `Space` | When focus is on the trigger, opens the select and focuses the first or selected item.
When focus is on an item, selects the focused item. | | `Enter` | When focus is on the trigger, opens the select and focuses the first or selected item.
When focus is on an item, selects the focused item. | | `ArrowDown` | When focus is on the trigger, opens the select and focuses the first or selected item.
When focus is on an item, moves focus to the next item. | | `ArrowUp` | When focus is on the trigger, opens the select and focuses the last or selected item.
When focus is on an item, moves focus to the previous item. | | `Home` | When focus is on an item, moves focus to first item. | | `End` | When focus is on an item, moves focus to last item. | | `ArrowRight` | In `Select`, when focus is on the trigger, change the selection to the next item. | | `ArrowLeft` | In `Select`, when focus is on the trigger, change the selection to the previous item. | | `Shift` \+ `ArrowDown` | In `Select`, moves focus to and toggles the selected state of the next item. | | `Shift` \+ `ArrowUp` | In `Select`, moves focus to and toggles the selected state of the previous item. | | `Shift` \+ `Space` | In `Select`, selects contiguous items from the most recently selected item to the focused item. | | `Ctrl` \+ `Shift` \+ `Home` | In `Select`, selects the focused item and all options up to the first item. | | `Ctrl` \+ `Shift` \+ `End` | In `Select`, selects the focused item and all options down to the last item. | | `Ctrl` \+ `A` | In `Select`, selects all item in the list. | | `Esc` | Closes the select and moves focus to the trigger. | Previous[←Segmented Control](https://kobalte.dev/docs/core/components/segmented-control)Next[Separator→](https://kobalte.dev/docs/core/components/separator)