# Select URL: https://ark-ui.com/docs/components/select Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/select.mdx Displays a list of options for the user to pick from. --- ## Anatomy ```tsx ``` ## Examples **Example: basic** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const frameworks = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Solid', value: 'solid' }, { label: 'Vue', value: 'vue' }, { label: 'Svelte', value: 'svelte' }, ], }, ); export component Basic() { {'Framework'}
{'Frameworks'} for (const item of frameworks.items; key item.value) { {item.label} {'✓'} }
} ``` ### Controlled Use the `value` and `onValueChange` props to control the selected items. **Example: controlled** ```ripple import { Portal } from 'ark-ripple/portal'; import { track } from 'ripple'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; interface Item { label: string; value: string; disabled?: boolean | undefined; } const collection = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Solid', value: 'solid' }, { label: 'Vue', value: 'vue' }, { label: 'Svelte', value: 'svelte', disabled: true }, ], }, ); export component Controlled() { let value = track([]); const setValue = (v: string[]) => { @value = v; }; setValue(e.value)} > {'Framework'}
{'Frameworks'} for (const item of collection.items; key item.value) { {item.label} {'✓'} }
} ``` ### 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. **Example: root-provider** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection, useSelect } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const frameworks = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Solid', value: 'solid' }, { label: 'Vue', value: 'vue' }, { label: 'Svelte', value: 'svelte' }, ], }, ); export component RootProvider() { const select = useSelect({ collection: frameworks });
{'selected: '} {JSON.stringify(@select.value)} {'Framework'}
{'Frameworks'} for (const item of frameworks.items; key item.value) { {item.label} {'✓'} }
} ``` ### Multiple To enable `multiple` item selection: **Example: multiple** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const frameworks = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Solid', value: 'solid' }, { label: 'Vue', value: 'vue' }, { label: 'Svelte', value: 'svelte', disabled: true }, ], }, ); export component Multiple() { {'Framework'}
{'Frameworks'} for (const item of frameworks.items; key item.value) { {item.label} {'✓'} }
} ``` ### Grouping Grouping related options can be useful for organizing options into categories. - Use the `groupBy` prop to configure the grouping of the items. - Use the `collection.group()` method to get the grouped items. - Use the `Select.ItemGroup` and `Select.ItemGroupLabel` components to render the grouped items. **Example: grouping** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const frameworks = createListCollection( { items: [ { label: 'React', value: 'react', type: 'JS' }, { label: 'Solid', value: 'solid', type: 'JS' }, { label: 'Vue', value: 'vue', type: 'JS' }, { label: 'Panda', value: 'panda', type: 'CSS' }, { label: 'Tailwind', value: 'tailwind', type: 'CSS' }, ], groupBy: (item: any) => item.type, }, ); export component Grouping() { {'Framework'}
for (const [type, group] of frameworks.group(); key type) { {type} for (const item of group; key item.value) { {item.label} {'✓'} } }
} ``` ### Field Use `Field` to manage form state, ARIA labels, helper text, and error text. **Example: with-field** ```ripple import { Select, createListCollection } from 'ark-ripple/select'; import { Field } from 'ark-ripple/field'; import { ChevronsUpDown } from 'lucide-ripple'; import field from 'styles/field.module.css'; import styles from 'styles/select.module.css'; const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] }); export component WithField() { {'Label'} for (const item of collection.items; key item) { {item} {'✓'} } {'Additional Info'} {'Error Info'} } ``` ### Form Usage Here's an example of integrating the `Select` component with a form library. **Example: form-library** ```ripple import { Portal } from 'ark-ripple/portal'; import { track } from 'ripple'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import button from 'styles/button.module.css'; import styles from 'styles/select.module.css'; const collection = createListCollection( { items: ['React', 'Solid', 'Vue', 'Svelte'], }, ); export component FormLibrary() { let value = track(['React']); const setValue = (v: string[]) => { @value = v; }; const handleSubmit = (e: any) => { e.preventDefault(); window.alert(JSON.stringify(new FormData(e.currentTarget).getAll('framework'))); }; // TODO: Add form library instead of native form
setValue(e.value)} > {'Framework'}
{'Frameworks'} for (const item of collection.items; key item) { {item} {'✓'} }
} ``` ### Async Loading Here's an example of how to load the items asynchronously when the select is opened. **Example: async** ```ripple import { Portal } from 'ark-ripple/portal'; import { track } from 'ripple'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown } from 'lucide-ripple'; import styles from 'styles/select.module.css'; function loadData() { return new Promise((resolve) => { setTimeout(() => resolve(['React', 'Solid', 'Vue', 'Svelte', 'Angular', 'Ember']), 500); }); } export component Async() { let data = track(null); let loading = track(false); let error = track(null); const collection = track(() => createListCollection({ items: @data ?? [] })); const setData = (v: string[] | null) => { @data = v; }; const setLoading = (v: boolean) => { @loading = v; }; const setError = (v: Error | null) => { @error = v; }; const handleOpenChange = (details: any) => { if (details.open && @data === null) { setLoading(true); setError(null); loadData().then((data) => setData(data)).catch((err) => setError(err)).finally( () => setLoading(false), ); } }; {'Framework'} if (@loading) {
{'Loading...'}
} else if (@error) {
{'Error: '} {@error.message}
} else { for (const item of @collection.items; key item) { {item} {'✓'} } }
} ``` ### Lazy Mount Use `lazyMount` and `unmountOnExit` to control when content is mounted, improving performance. **Example: lazy-mount** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const collection = createListCollection( { items: ['React', 'Solid', 'Vue', 'Svelte', 'Angular', 'Alpine'], }, ); export component LazyMount() { {'Framework'} {'Clear'} {'Frameworks'} for (const item of collection.items; key item) { {item} {'✓'} } } ``` ### Select on Highlight Here's an example of automatically selecting items when they are highlighted (hovered or navigated to with keyboard). **Example: select-on-highlight** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection, useSelect } from 'ark-ripple/select'; import { ChevronsUpDown } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const collection = createListCollection( { items: ['React', 'Solid', 'Vue', 'Svelte'], }, ); export component SelectOnHighlight() { const select = useSelect( { collection, onHighlightChange(details: any) { if (details.highlightedValue) { @select.selectValue(details.highlightedValue); } }, }, ); {'Framework'} {'Clear'} {'Frameworks'} for (const item of collection.items; key item) { {item} {'✓'} } } ``` ### Max Selection Here's an example of limiting the number of items that can be selected in a multiple select. **Example: max-selected** ```ripple import { Portal } from 'ark-ripple/portal'; import { track } from 'ripple'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown, X } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const items = ['React', 'Solid', 'Vue', 'Svelte']; const MAX_SELECTION = 2; const hasReachedMax = (value: string[]) => value.length >= MAX_SELECTION; export component MaxSelected() { let value = track([]); const setValue = (v: string[]) => { @value = v; }; const collection = track( () => createListCollection( { items: items.map( (item) => ({ label: item, value: item, disabled: hasReachedMax(@value) && !@value.includes(item), }), ), }, ), ); const handleValueChange = (details: Select.ValueChangeDetails) => { if (hasReachedMax(@value) && details.value.length > @value.length) return; setValue(details.value); }; {'Framework'} {'Frameworks'} for (const item of @collection.items; key item.value) { {item.label} {'✓'} } } ``` ### Select All Use `selectAll()` from the select context to select all items at once. **Example: select-all** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection, useSelectContext } from 'ark-ripple/select'; import { ChevronsUpDown } from 'lucide-ripple'; import button from 'styles/button.module.css'; import styles from 'styles/select.module.css'; component SelectAllButton() { const select = useSelectContext(); component children({ context }) { } } export component SelectAll() { const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] }); {'Framework'} {'Clear'} for (const item of collection.items; key item) { {item} {'✓'} } } ``` ### 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. **Example: overflow** ```ripple import { Portal } from 'ark-ripple/portal'; import { Select, createListCollection } from 'ark-ripple/select'; import { ChevronsUpDown } from 'lucide-ripple'; import styles from 'styles/select.module.css'; const collection = createListCollection( { items: [ 'Name 1', 'Name 2', 'Name 3', 'Name 4', 'Name 5', 'Name 6', 'Name 7', 'Name 8', 'Name 9', 'Name 10', 'Name 11', 'Name 12', 'Name 13', 'Name 14', ], }, ); export component Overflow() { {'Framework'} {'Clear'} {'Names'} for (const item of collection.items; key item) { {item} {'✓'} } } ``` ## Guides ### 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 `` 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 ```tsx {/* Other Select components */} ``` 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: ```tsx component SelectEmpty(props) { const select = useSelectContext() if (@select.collection.size === 0) {
} } ``` Then use it within your Select content: ```tsx {"No items to display"} {/* Your items */} ``` ### Available Size The following css variables are exposed to the `Select.Positioner` which you can use to style the `Select.Content` ```css /* width of the select trigger */ --reference-width: ; /* width of the available viewport */ --available-width: ; /* height of the available viewport */ --available-height: ; ``` For example, if you want to make sure the maximum height doesn't exceed the available height, you can use the following: ```css [data-scope='select'][data-part='content'] { max-height: calc(var(--available-height) - 100px); } ``` ## API Reference ### Props **Component API Reference** **Root Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `collection` | `ListCollection` | Yes | The collection of items | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `autoComplete` | `string` | No | The autocomplete attribute for the hidden select. Enables browser autofill (e.g. "address-level1" for state). | | `closeOnSelect` | `boolean` | No | Whether the select should close after an item is selected | | `composite` | `boolean` | No | Whether the select is a composed with other composite widgets like tabs or combobox | | `defaultHighlightedValue` | `string` | No | The initial value of the highlighted item when opened. Use when you don't need to control the highlighted value of the select. | | `defaultOpen` | `boolean` | No | Whether the select's open state is controlled by the user | | `defaultValue` | `string[]` | No | The initial default value of the select when rendered. Use when you don't need to control the value of the select. | | `deselectable` | `boolean` | No | Whether the value can be cleared by clicking the selected item. **Note:** this is only applicable for single selection | | `disabled` | `boolean` | No | Whether the select is disabled | | `form` | `string` | No | The associate form of the underlying select. | | `highlightedValue` | `string` | No | The controlled key of the highlighted item | | `id` | `string` | No | The 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 }>` | No | The ids of the elements in the select. Useful for composition. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `invalid` | `boolean` | No | Whether the select is invalid | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `loopFocus` | `boolean` | No | Whether to loop the keyboard navigation through the options | | `multiple` | `boolean` | No | Whether to allow multiple selection | | `name` | `string` | No | The `name` attribute of the underlying select. | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `onFocusOutside` | `(event: FocusOutsideEvent) => void` | No | Function called when the focus is moved outside the component | | `onHighlightChange` | `(details: HighlightChangeDetails) => void` | No | The callback fired when the highlighted item changes. | | `onInteractOutside` | `(event: InteractOutsideEvent) => void` | No | Function called when an interaction happens outside the component | | `onOpenChange` | `(details: OpenChangeDetails) => void` | No | Function called when the popup is opened | | `onPointerDownOutside` | `(event: PointerDownOutsideEvent) => void` | No | Function called when the pointer is pressed down outside the component | | `onSelect` | `(details: SelectionDetails) => void` | No | Function called when an item is selected | | `onValueChange` | `(details: ValueChangeDetails) => void` | No | The callback fired when the selected item changes. | | `open` | `boolean` | No | Whether the select menu is open | | `positioning` | `PositioningOptions` | No | The positioning options of the menu. | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `readOnly` | `boolean` | No | Whether the select is read-only | | `required` | `boolean` | No | Whether the select is required | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | | `value` | `string[]` | No | The controlled keys of the selected items | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | select | | `[data-part]` | root | | `[data-invalid]` | Present when invalid | | `[data-readonly]` | Present when read-only | **ClearTrigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ClearTrigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | select | | `[data-part]` | clear-trigger | | `[data-invalid]` | Present when invalid | **Content Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Content Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--layer-index` | The index of the dismissable in the layer stack | | `--nested-layer-count` | The number of nested selects | **Control Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Control Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Indicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemGroup Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemGroup Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | select | | `[data-part]` | item-group | | `[data-disabled]` | Present when disabled | **ItemIndicator Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemIndicator Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | select | | `[data-part]` | item-indicator | | `[data-state]` | "checked" | "unchecked" | **Item Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `item` | `any` | No | The item to render | | `persistFocus` | `boolean` | No | Whether hovering outside should clear the highlighted state | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **ItemText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | select | | `[data-part]` | item-text | | `[data-state]` | "checked" | "unchecked" | | `[data-disabled]` | Present when disabled | | `[data-highlighted]` | Present when highlighted | **Label Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Label Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Positioner Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Positioner CSS Variables:** | 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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseSelectReturn` | Yes | | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `immediate` | `boolean` | No | Whether to synchronize the present change immediately or defer it to the next frame | | `lazyMount` | `boolean` | No | Whether to enable lazy mounting | | `onExitComplete` | `VoidFunction` | No | Function called when the animation ends in the closed state | | `present` | `boolean` | No | Whether the node is present (controlled by the user) | | `skipAnimationOnMount` | `boolean` | No | Whether to allow the initial presence animation. | | `unmountOnExit` | `boolean` | No | Whether to unmount on exit. | **Trigger Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Trigger Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `placeholder` | `string` | No | Text to display when no value is selected. | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[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 | Description | |----------|------|-------------| | `focused` | `boolean` | Whether the select is focused | | `open` | `boolean` | Whether the select is open | | `empty` | `boolean` | Whether the select value is empty | | `highlightedValue` | `string` | The value of the highlighted item | | `highlightedItem` | `V` | The highlighted item | | `setHighlightValue` | `(value: string) => void` | Function to highlight a value | | `clearHighlightValue` | `VoidFunction` | Function to clear the highlighted value | | `selectedItems` | `V[]` | The selected items | | `hasSelectedItems` | `boolean` | Whether there's a selected option | | `value` | `string[]` | The selected item keys | | `valueAsString` | `string` | The string representation of the selected items | | `selectValue` | `(value: string) => void` | Function to select a value | | `selectAll` | `VoidFunction` | Function to select all values | | `setValue` | `(value: string[]) => void` | Function to set the value of the select | | `clearValue` | `(value?: string) => void` | Function 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` | `VoidFunction` | Function to focus on the select input | | `getItemState` | `(props: ItemProps) => ItemState` | Returns the state of a select item | | `setOpen` | `(open: boolean) => void` | Function to open or close the select | | `collection` | `ListCollection` | Function to toggle the select | | `reposition` | `(options?: Partial) => void` | Function to set the positioning options of the select | | `multiple` | `boolean` | Whether the select allows multiple selections | | `disabled` | `boolean` | Whether the select is disabled | ## Accessibility Complies with the [Listbox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/). ### Keyboard Support