Listbox
A component for selecting a single or multiple items from a list.
Anatomy
To set up the Listbox correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Basic
Here's a basic example of the Listbox component.
import { Listbox, createListCollection } from '@ark-ui/react/listbox'
export const Basic = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{collection.items.map((item) => (
<Listbox.Item key={item} item={item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
))}
</Listbox.Content>
</Listbox.Root>
)
}
import { Listbox, createListCollection } from '@ark-ui/solid/listbox'
import { Index } from 'solid-js'
export const Basic = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Index each={collection.items}>
{(item) => (
<Listbox.Item item={item()}>
<Listbox.ItemText>{item()}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
)}
</Index>
</Listbox.Content>
</Listbox.Root>
)
}
<script setup lang="ts">
import { Listbox, createListCollection } from '@ark-ui/vue/listbox'
const collection = createListCollection({
items: ['React', 'Solid', 'Vue', 'Svelte'],
})
</script>
<template>
<Listbox.Root :collection="collection">
<Listbox.Label>Framework</Listbox.Label>
<Listbox.Content>
<Listbox.Item v-for="item in collection.items" :key="item" :item="item">
<Listbox.ItemText>{{ item }}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.Content>
</Listbox.Root>
</template>
<script lang="ts">
import { Listbox, createListCollection } from '@ark-ui/svelte/listbox'
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
</script>
<Listbox.Root {collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{#each collection.items as item}
<Listbox.Item {item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
{/each}
</Listbox.Content>
</Listbox.Root>
Controlled
The Listbox component can be controlled by using the value and onValueChange props. This allows you to manage the
selected value externally.
import { Listbox, createListCollection } from '@ark-ui/react/listbox'
import { useState } from 'react'
export const Controlled = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
const [value, setValue] = useState(['React'])
return (
<Listbox.Root value={value} onValueChange={(e) => setValue(e.value)} collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{collection.items.map((item) => (
<Listbox.Item key={item} item={item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
))}
</Listbox.Content>
</Listbox.Root>
)
}
import { Listbox, createListCollection } from '@ark-ui/solid/listbox'
import { Index, createSignal } from 'solid-js'
export const Controlled = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
const [value, setValue] = createSignal(['React'])
return (
<Listbox.Root value={value()} onValueChange={(e) => setValue(e.value)} collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Index each={collection.items}>
{(item) => (
<Listbox.Item item={item()}>
<Listbox.ItemText>{item()}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
)}
</Index>
</Listbox.Content>
</Listbox.Root>
)
}
<script setup lang="ts">
import { Listbox, createListCollection } from '@ark-ui/vue/listbox'
import { ref } from 'vue'
const collection = createListCollection({
items: ['React', 'Solid', 'Vue', 'Svelte'],
})
const value = ref(['React'])
</script>
<template>
<Listbox.Root :collection="collection" v-model="value">
<Listbox.Label>Framework</Listbox.Label>
<Listbox.Content>
<Listbox.Item v-for="item in collection.items" :key="item" :item="item">
<Listbox.ItemText>{{ item }}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.Content>
</Listbox.Root>
</template>
<script lang="ts">
import { Listbox, createListCollection } from '@ark-ui/svelte/listbox'
const collection = createListCollection({
items: ['React', 'Solid', 'Vue', 'Svelte'],
})
let value = $state(['React'])
</script>
<Listbox.Root bind:value {collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{#each collection.items as item (item)}
<Listbox.Item {item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
{/each}
</Listbox.Content>
</Listbox.Root>
Disabled Item
Listbox items can be disabled using the disabled prop on the collection item.
import { Listbox, createListCollection } from '@ark-ui/react/listbox'
export const Disabled = () => {
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Svelte', value: 'svelte', disabled: true },
{ label: 'Vue', value: 'vue' },
],
})
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{collection.items.map((item) => (
<Listbox.Item key={item.value} item={item}>
<Listbox.ItemText>{item.label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
))}
</Listbox.Content>
</Listbox.Root>
)
}
import { Listbox, createListCollection } from '@ark-ui/solid/listbox'
import { Index } from 'solid-js'
export const Disabled = () => {
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Svelte', value: 'svelte', disabled: true },
{ label: 'Vue', value: 'vue' },
],
})
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Index each={collection.items}>
{(item) => (
<Listbox.Item item={item()}>
<Listbox.ItemText>{item().label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
)}
</Index>
</Listbox.Content>
</Listbox.Root>
)
}
<script setup lang="ts">
import { Listbox, createListCollection } from '@ark-ui/vue/listbox'
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Svelte', value: 'svelte', disabled: true },
{ label: 'Vue', value: 'vue' },
],
})
</script>
<template>
<Listbox.Root :collection="collection">
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Listbox.Item v-for="item in collection.items" :key="item.value" :item="item">
<Listbox.ItemText>{{ item.label }}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.Content>
</Listbox.Root>
</template>
<script lang="ts">
import { Listbox, createListCollection } from '@ark-ui/svelte/listbox'
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Svelte', value: 'svelte', disabled: true },
{ label: 'Vue', value: 'vue' },
],
})
</script>
<Listbox.Root {collection}>
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{#each collection.items as item (item.value)}
<Listbox.Item {item}>
<Listbox.ItemText>{item.label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
{/each}
</Listbox.Content>
</Listbox.Root>
You can also use the
isItemDisabledwithin thecreateListCollectionto disable items based on a condition.
Multiple Selection
You can set the selectionMode property as multiple to allow the user to select multiple items at a time.
import { Listbox, createListCollection } from '@ark-ui/react/listbox'
export const Multiple = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
return (
<Listbox.Root collection={collection} selectionMode="multiple">
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
{collection.items.map((item) => (
<Listbox.Item key={item} item={item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
))}
</Listbox.Content>
</Listbox.Root>
)
}
import { Listbox, createListCollection } from '@ark-ui/solid/listbox'
import { Index } from 'solid-js'
export const Multiple = () => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
return (
<Listbox.Root collection={collection} selectionMode="multiple">
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Index each={collection.items}>
{(item) => (
<Listbox.Item item={item()}>
<Listbox.ItemText>{item()}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
)}
</Index>
</Listbox.Content>
</Listbox.Root>
)
}
<script setup lang="ts">
import { Listbox, createListCollection } from '@ark-ui/vue/listbox'
const collection = createListCollection({
items: ['React', 'Solid', 'Vue', 'Svelte'],
})
</script>
<template>
<Listbox.Root :collection="collection" selectionMode="multiple">
<Listbox.Label>Select your Framework</Listbox.Label>
<Listbox.Content>
<Listbox.Item v-for="item in collection.items" :key="item" :item="item">
<Listbox.ItemText>{{ item }}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.Content>
</Listbox.Root>
</template>
<script lang="ts">
import { Listbox, createListCollection } from '@ark-ui/svelte/listbox'
const collection = createListCollection({ items: ['React', 'Solid', 'Vue', 'Svelte'] })
let value = $state(['React'])
</script>
<Listbox.Root {collection} bind:value selectionMode="multiple">
<Listbox.Label>Select your Frameworks (Multiple)</Listbox.Label>
<Listbox.ValueText placeholder="Select frameworks..." />
<Listbox.Content>
{#each collection.items as item}
<Listbox.Item {item}>
<Listbox.ItemText>{item}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
{/each}
</Listbox.Content>
</Listbox.Root>
<div>
<p>Selected: {JSON.stringify(value)}</p>
</div>
Grouping
The Listbox component supports grouping items. You can use the groupBy function to group items based on a specific
property.
import { Listbox, createListCollection } from '@ark-ui/react/listbox'
export const Group = () => {
const collection = 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) => item.type,
})
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Frameworks</Listbox.Label>
<Listbox.Content>
{collection.group().map(([type, group]) => (
<Listbox.ItemGroup key={type}>
<Listbox.ItemGroupLabel>{type}</Listbox.ItemGroupLabel>
{group.map((item) => (
<Listbox.Item key={item.value} item={item}>
<Listbox.ItemText>{item.label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
))}
</Listbox.ItemGroup>
))}
</Listbox.Content>
</Listbox.Root>
)
}
import { Listbox, createListCollection } from '@ark-ui/solid/listbox'
import { For } from 'solid-js'
export const Group = () => {
const collection = 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) => item.type,
})
return (
<Listbox.Root collection={collection}>
<Listbox.Label>Select your Frameworks</Listbox.Label>
<Listbox.Content>
<For each={collection.group()}>
{([type, group]) => (
<Listbox.ItemGroup>
<Listbox.ItemGroupLabel>{type}</Listbox.ItemGroupLabel>
<For each={group}>
{(item) => (
<Listbox.Item item={item}>
<Listbox.ItemText>{item.label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
)}
</For>
</Listbox.ItemGroup>
)}
</For>
</Listbox.Content>
</Listbox.Root>
)
}
<script setup lang="ts">
import { Listbox, createListCollection } from '@ark-ui/vue/listbox'
const collection = 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) => item.type,
})
</script>
<template>
<Listbox.Root :collection="collection">
<Listbox.Label>Select your Frameworks</Listbox.Label>
<Listbox.Content>
<Listbox.ItemGroup v-for="[type, group] in collection.group()" :key="type">
<Listbox.ItemGroupLabel>{{ type }}</Listbox.ItemGroupLabel>
<Listbox.Item v-for="item in group" :key="item.value" :item="item">
<Listbox.ItemText>{{ item.label }}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
</Listbox.ItemGroup>
</Listbox.Content>
</Listbox.Root>
</template>
<script lang="ts">
import { Listbox, createListCollection } from '@ark-ui/svelte/listbox'
const collection = createListCollection({
items: [
{ label: 'React', value: 'react', type: 'JS' },
{ label: 'Solid', value: 'solid', type: 'JS' },
{ label: 'Vue', value: 'vue', type: 'JS' },
{ label: 'Svelte', value: 'svelte', type: 'JS' },
{ label: 'Panda', value: 'panda', type: 'CSS' },
{ label: 'Tailwind', value: 'tailwind', type: 'CSS' },
],
groupBy: (item) => item.type,
})
</script>
<Listbox.Root {collection}>
<Listbox.Label>Select your Frameworks</Listbox.Label>
<Listbox.Content>
{#each collection.group() as [type, group]}
<Listbox.ItemGroup>
<Listbox.ItemGroupLabel>{type}</Listbox.ItemGroupLabel>
{#each group as item}
<Listbox.Item {item}>
<Listbox.ItemText>{item.label}</Listbox.ItemText>
<Listbox.ItemIndicator />
</Listbox.Item>
{/each}
</Listbox.ItemGroup>
{/each}
</Listbox.Content>
</Listbox.Root>
Guides
Type-Safety
The Listbox.RootComponent type enables you to create closed, strongly typed wrapper components that maintain full type
safety for collection items.
This is particularly useful when building reusable listbox components with custom props and consistent styling.
import { Listbox as ArkListbox, type CollectionItem } from '@ark-ui/react/listbox'
import { createListCollection } from '@ark-ui/react/collection'
interface ListboxProps<T extends CollectionItem> extends ArkListbox.RootProps<T> {}
const Listbox: ArkListbox.RootComponent = (props) => {
return <ArkListbox.Root {...props}>{/* ... */}</ArkListbox.Root>
}
Then, you can use the Listbox component as follows:
const App = () => {
const collection = createListCollection({
initialItems: [
{ label: 'React', value: 'react' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte' },
],
})
return (
<Listbox
collection={collection}
onValueChange={(e) => {
// this will be strongly typed Array<{ label: string, value: string }>
console.log(e.items)
}}
>
{/* ... */}
</Listbox>
)
}
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. | |
defaultHighlightedValue | stringThe initial value of the highlighted item when opened. Use when you don't need to control the highlighted value of the listbox. | |
defaultValue | [] | string[]The initial default value of the listbox when rendered. Use when you don't need to control the value of the listbox. |
deselectable | booleanWhether to disallow empty selection | |
disabled | booleanWhether the listbox is disabled | |
disallowSelectAll | booleanWhether to disallow selecting all items when `meta+a` is pressed | |
highlightedValue | stringThe controlled key of the highlighted item | |
id | stringThe 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
}>The ids of the elements in the listbox. Useful for composition. | |
loopFocus | false | booleanWhether to loop the keyboard navigation through the options |
onHighlightChange | (details: HighlightChangeDetails<T>) => voidThe callback fired when the highlighted item changes. | |
onSelect | (details: SelectionDetails) => voidFunction called when an item is selected | |
onValueChange | (details: ValueChangeDetails<T>) => voidThe callback fired when the selected item changes. | |
orientation | 'vertical' | 'horizontal' | 'vertical'The orientation of the listbox. |
scrollToIndexFn | (details: ScrollToIndexDetails) => voidFunction to scroll to a specific index | |
selectionMode | 'single' | SelectionModeHow 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 | booleanWhether to select the item when it is highlighted | |
typeahead | booleanWhether to enable typeahead on the listbox | |
value | string[]The controlled keys of the selected items |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | root |
[data-orientation] | The orientation of the listbox |
[data-disabled] | Present when disabled |
Content
| 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 |
|---|---|
--column-count | The column count value for the Content |
| Data 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 |
Empty
| 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. |
Input
| 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. | |
autoHighlight | false | booleanWhether to automatically highlight the item when typing |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | input |
[data-disabled] | Present when disabled |
ItemGroupLabel
| 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
| 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. |
| Data 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
| 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. |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | item-indicator |
[data-state] | "checked" | "unchecked" |
Item
| 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. | |
highlightOnHover | booleanWhether to highlight the item on hover | |
item | anyThe item to render |
| Data 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
| 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. |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | item-text |
[data-state] | "checked" | "unchecked" |
[data-disabled] | Present when disabled |
[data-highlighted] | Present when highlighted |
Label
| 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. |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | label |
[data-disabled] | Present when disabled |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UseListboxReturn<T> | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
ValueText
| 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 listboxed. |
| Data Attribute | Value |
|---|---|
[data-scope] | listbox |
[data-part] | value-text |
[data-disabled] | Present when disabled |
Context
These are the properties available when using Listbox.Context, useListboxContext hook or useListbox hook.
API
| Property | Type |
|---|---|
empty | booleanWhether the select value is empty |
highlightedValue | stringThe value of the highlighted item |
highlightedItem | VThe highlighted item |
highlightValue | (value: string) => voidFunction to highlight a value |
clearHighlightedValue | 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. **Note**: This should only be called when the selectionMode is `multiple` or `extended`. Otherwise, an exception will be thrown. |
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. |
getItemState | (props: ItemProps<any>) => ItemStateReturns the state of a select item |
collection | ListCollection<V>Function to toggle the select |
disabled | booleanWhether the select is disabled |