# Listbox URL: https://ark-ui.com/docs/components/listbox Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/listbox.mdx A component for selecting a single or multiple items from a list. --- ## Anatomy {/* */} ```tsx ``` ## Examples ### Basic Here's a basic example of the Listbox component. **Example: basic** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component Basic() { const collection = createListCollection( { items: [ { label: 'United States', value: 'us' }, { label: 'United Kingdom', value: 'uk' }, { label: 'Canada', value: 'ca' }, { label: 'Australia', value: 'au' }, { label: 'Germany', value: 'de' }, { label: 'France', value: 'fr' }, { label: 'Japan', value: 'jp' }, ], }, ); {'Select Country'} for (const item of collection.items; key item.value) { {item.label} } } ``` ### Controlled The Listbox component can be controlled by using the `value` and `onValueChange` props. This allows you to manage the selected value externally. **Example: controlled** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import { track } from 'ripple'; import styles from 'styles/listbox.module.css'; export component Controlled() { const collection = createListCollection( { items: [ { label: 'Small', value: 'sm' }, { label: 'Medium', value: 'md' }, { label: 'Large', value: 'lg' }, { label: 'Extra Large', value: 'xl' }, ], }, ); let value = track(['md']); { @value = e.value; }} > {'Select Size'} for (const item of collection.items; key item.value) { {item.label} } } ``` ### Root Provider An alternative way to control the listbox is to use the `RootProvider` component and the `useListbox` hook. This way you can access the state and methods from outside the component. **Example: root-provider** ```ripple import { Listbox, createListCollection, useListbox } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import button from 'styles/button.module.css'; import styles from 'styles/listbox.module.css'; export component RootProvider() { const collection = createListCollection( { items: [ { label: 'Low', value: 'low' }, { label: 'Medium', value: 'medium' }, { label: 'High', value: 'high' }, { label: 'Critical', value: 'critical' }, ], }, ); const listbox = useListbox({ collection });
{'Select Priority'} for (const item of collection.items; key item.value) { {item.label} }
} ``` ### Disabled Item Listbox items can be disabled using the `disabled` prop on the collection item. **Example: disabled-item** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component DisabledItem() { const collection = createListCollection( { items: [ { label: 'Free', value: 'free' }, { label: 'Pro', value: 'pro' }, { label: 'Enterprise', value: 'enterprise', disabled: true }, { label: 'Custom', value: 'custom' }, ], }, ); {'Select Plan'} for (const item of collection.items; key item.value) { {item.label} } } ``` > You can also use the `isItemDisabled` within the `createListCollection` to disable items based on a condition. ### Multiple You can set the `selectionMode` property as `multiple` to allow the user to select multiple items at a time. **Example: multiple** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component Multiple() { const collection = createListCollection( { items: [ { label: 'Monday', value: 'mon' }, { label: 'Tuesday', value: 'tue' }, { label: 'Wednesday', value: 'wed' }, { label: 'Thursday', value: 'thu' }, { label: 'Friday', value: 'fri' }, { label: 'Saturday', value: 'sat' }, { label: 'Sunday', value: 'sun' }, ], }, ); {'Select Days'} for (const item of collection.items; key item.value) { {item.label} } } ``` ### Grouping The Listbox component supports grouping items. You can use the `groupBy` function to group items based on a specific property. **Example: group** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component Group() { const collection = createListCollection( { items: [ { label: 'New York', value: 'nyc', region: 'North America' }, { label: 'Los Angeles', value: 'lax', region: 'North America' }, { label: 'Toronto', value: 'yyz', region: 'North America' }, { label: 'London', value: 'lhr', region: 'Europe' }, { label: 'Paris', value: 'cdg', region: 'Europe' }, { label: 'Berlin', value: 'ber', region: 'Europe' }, { label: 'Tokyo', value: 'nrt', region: 'Asia Pacific' }, { label: 'Singapore', value: 'sin', region: 'Asia Pacific' }, { label: 'Sydney', value: 'syd', region: 'Asia Pacific' }, ], groupBy: (item) => item.region, }, ); {'Select Region'} for (const [region, items] of collection.group(); key region) { {region} for (const item of items; key item.value) { {item.label} } } } ``` ### Extended Selection The extended selection mode allows users to select multiple items using keyboard modifiers like `Cmd` (Mac) or `Ctrl` (Windows/Linux). **Example: extended-select** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component ExtendedSelect() { const collection = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Vue', value: 'vue' }, { label: 'Angular', value: 'angular' }, { label: 'Svelte', value: 'svelte' }, { label: 'Solid', value: 'solid' }, { label: 'Preact', value: 'preact' }, ], }, ); {'Hold '} {'⌘'} {' or '} {'Ctrl'} {' to select multiple'} for (const item of collection.items; key item.value) { {item.label} } } ``` ### Horizontal Use the `orientation` prop to display the listbox items horizontally. **Example: horizontal** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component Horizontal() { const collection = createListCollection( { items: [ { title: 'Midnight Dreams', artist: 'Luna Ray', image: 'https://picsum.photos/seed/album1/300/300', }, { title: 'Neon Skyline', artist: 'The Electric', image: 'https://picsum.photos/seed/album2/300/300', }, { title: 'Acoustic Sessions', artist: 'Sarah Woods', image: 'https://picsum.photos/seed/album3/300/300', }, { title: 'Urban Echoes', artist: 'Metro Collective', image: 'https://picsum.photos/seed/album4/300/300', }, { title: 'Summer Vibes', artist: 'Coastal Waves', image: 'https://picsum.photos/seed/album5/300/300', }, ], itemToValue: (item) => item.title, itemToString: (item) => item.title, }, ); {'Select Album'} for (const item of collection.items; key item.title) { {item.title} {item.title} {item.artist} } } ``` ### Grid Layout Use `createGridCollection` to display items in a grid layout with keyboard navigation support. **Example: grid** ```ripple import { createGridCollection } from 'ark-ripple/collection'; import { Listbox } from 'ark-ripple/listbox'; import styles from 'styles/listbox.module.css'; export component Grid() { const collection = createGridCollection( { items: [ { label: '😀', value: 'grinning' }, { label: '😍', value: 'heart-eyes' }, { label: '🥳', value: 'partying' }, { label: '😎', value: 'sunglasses' }, { label: '🤩', value: 'star-struck' }, { label: '😂', value: 'joy' }, { label: '🥰', value: 'smiling-hearts' }, { label: '😊', value: 'blush' }, { label: '🤗', value: 'hugging' }, { label: '😇', value: 'innocent' }, { label: '🔥', value: 'fire' }, { label: '✨', value: 'sparkles' }, { label: '💯', value: 'hundred' }, { label: '🎉', value: 'tada' }, { label: '❤️', value: 'heart' }, { label: '👍', value: 'thumbs-up' }, { label: '👏', value: 'clap' }, { label: '🚀', value: 'rocket' }, { label: '⭐', value: 'star' }, { label: '🌈', value: 'rainbow' }, ], columnCount: 5, }, ); {'Pick a reaction'} for (const item of collection.items; key item.value) { {item.label} } } ``` ### Filtering Use `useListCollection` with the `filter` function to enable filtering of items. **Example: filtering** ```ripple import { useListCollection } from 'ark-ripple/collection'; import { Listbox } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import field from 'styles/field.module.css'; import styles from 'styles/listbox.module.css'; export component Filtering() { const { collection, filter } = useListCollection( { initialItems: [ { label: 'React', value: 'react' }, { label: 'Vue', value: 'vue' }, { label: 'Angular', value: 'angular' }, { label: 'Svelte', value: 'svelte' }, { label: 'Solid', value: 'solid' }, { label: 'Next.js', value: 'nextjs' }, { label: 'Nuxt.js', value: 'nuxtjs' }, { label: 'Remix', value: 'remix' }, { label: 'Gatsby', value: 'gatsby' }, { label: 'Preact', value: 'preact' }, ], filter: (itemText, filterText) => itemText.toLowerCase().includes(filterText.toLowerCase()), }, ); {'Select Framework'} filter((e.target as HTMLInputElement).value)} /> for (const item of @collection.items; key item.value) { {item.label} } {'No frameworks found'} } ``` ### Select All Use `useListboxContext` to implement a "Select All" functionality that allows users to select or deselect all items at once. **Example: select-all** ```ripple import { Listbox, createListCollection, useListboxContext } from 'ark-ripple/listbox'; import { Check, Minus } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; const frameworks = createListCollection( { items: [ { label: 'React', value: 'react' }, { label: 'Vue', value: 'vue' }, { label: 'Angular', value: 'angular' }, { label: 'Svelte', value: 'svelte' }, { label: 'Next.js', value: 'nextjs' }, { label: 'Nuxt.js', value: 'nuxtjs' }, { label: 'Remix', value: 'remix' }, { label: 'Gatsby', value: 'gatsby' }, ], }, ); component SelectAllHeader() { const listbox = useListboxContext(); const isAllSelected = @listbox.value.length === frameworks.items.length; const isSomeSelected = @listbox.value.length > 0 && @listbox.value.length < frameworks.items.length; const handleSelectAll = () => { if (isAllSelected) { @listbox.setValue([]); } else { @listbox.setValue(frameworks.items.map((item) => item.value)); } }; } export component SelectAll() { for (const item of frameworks.items; key item.value) { {item.label} } } ``` ### Value Text Use `Listbox.ValueText` to display the selected values as a comma-separated string. **Example: value-text** ```ripple import { Listbox, createListCollection } from 'ark-ripple/listbox'; import { Check } from 'lucide-ripple'; import styles from 'styles/listbox.module.css'; export component ValueText() { const collection = createListCollection( { items: [ { label: 'Red', value: 'red' }, { label: 'Blue', value: 'blue' }, { label: 'Green', value: 'green' }, { label: 'Yellow', value: 'yellow' }, { label: 'Purple', value: 'purple' }, ], }, ); {'Colors: '} for (const item of collection.items; key item.value) { {item.label} } } ``` ## 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. | | `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 listbox. | | `defaultValue` | `string[]` | No | The initial default value of the listbox when rendered. Use when you don't need to control the value of the listbox. | | `deselectable` | `boolean` | No | Whether to disallow empty selection | | `disabled` | `boolean` | No | Whether the listbox is disabled | | `disallowSelectAll` | `boolean` | No | Whether to disallow selecting all items when `meta+a` is pressed | | `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 label: string item: (id: string | number) => string itemGroup: (id: string | number) => string itemGroupLabel: (id: string | number) => string }>` | No | The ids of the elements in the listbox. Useful for composition. | | `loopFocus` | `boolean` | No | Whether to loop the keyboard navigation through the options | | `onHighlightChange` | `(details: HighlightChangeDetails) => void` | No | The callback fired when the highlighted item changes. | | `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. | | `orientation` | `'horizontal' | 'vertical'` | No | The orientation of the listbox. | | `scrollToIndexFn` | `(details: ScrollToIndexDetails) => void` | No | Function to scroll to a specific index | | `selectionMode` | `SelectionMode` | No | How multiple selection should behave in the listbox. - `single`: The user can select a single item. - `multiple`: The user can select multiple items without using modifier keys. - `extended`: The user can select multiple items by using modifier keys. | | `selectOnHighlight` | `boolean` | No | Whether to select the item when it is highlighted | | `typeahead` | `boolean` | No | Whether to enable typeahead on the listbox | | `value` | `string[]` | No | The controlled keys of the selected items | **Root Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | listbox | | `[data-part]` | root | | `[data-orientation]` | The orientation of the listbox | | `[data-disabled]` | Present when disabled | **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]` | listbox | | `[data-part]` | content | | `[data-activedescendant]` | The id the active descendant of the content | | `[data-orientation]` | The orientation of the content | | `[data-layout]` | | | `[data-empty]` | Present when the content is empty | **Content CSS Variables:** | Variable | Description | |----------|-------------| | `--column-count` | The column count value for the Content | **Empty Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **Input Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | | `autoHighlight` | `boolean` | No | Whether to automatically highlight the item when typing | **Input Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | listbox | | `[data-part]` | input | | `[data-disabled]` | Present when disabled | **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]` | listbox | | `[data-part]` | item-group | | `[data-disabled]` | Present when disabled | | `[data-orientation]` | The orientation of the item | | `[data-empty]` | Present when the content is empty | **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]` | listbox | | `[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. | | `highlightOnHover` | `boolean` | No | Whether to highlight the item on hover | | `item` | `any` | No | The item to render | **Item Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | listbox | | `[data-part]` | item | | `[data-value]` | The value of the item | | `[data-selected]` | Present when selected | | `[data-layout]` | | | `[data-state]` | "checked" | "unchecked" | | `[data-orientation]` | The orientation of the item | | `[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]` | listbox | | `[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]` | listbox | | `[data-part]` | label | | `[data-disabled]` | Present when disabled | **RootProvider Props:** | Prop | Type | Required | Description | |------|------|----------|-------------| | `value` | `UseListboxReturn` | Yes | | | `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. | **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 listboxed. | **ValueText Data Attributes:** | Attribute | Value | |-----------|-------| | `[data-scope]` | listbox | | `[data-part]` | value-text | | `[data-disabled]` | Present when disabled | ### Context **API:** | Property | Type | Description | |----------|------|-------------| | `empty` | `boolean` | Whether the select value is empty | | `highlightedValue` | `string` | The value of the highlighted item | | `highlightedItem` | `V` | The highlighted item | | `highlightValue` | `(value: string) => void` | Function to highlight a value | | `clearHighlightedValue` | `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. **Note**: This should only be called when the selectionMode is `multiple` or `extended`. Otherwise, an exception will be thrown. | | `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. | | `getItemState` | `(props: ItemProps) => ItemState` | Returns the state of a select item | | `collection` | `ListCollection` | Function to toggle the select | | `disabled` | `boolean` | Whether the select is disabled |