{"slug":"listbox","title":"Listbox","description":"Used to display a list of selectable options, supporting both single and multiple selection modes.","contentType":"component","framework":"svelte","content":"A listbox displays selectable options in single or multiple selection modes.\n\n## Resources\n\n\n[Latest version: v1.39.1](https://www.npmjs.com/package/@zag-js/listbox)\n[Logic Visualizer](https://zag-visualizer.vercel.app/listbox)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/listbox)\n\n\n\n**Features**\n\n- Supports single, multiple, or no selection\n- Can be controlled or uncontrolled\n- Fully managed keyboard navigation (arrow keys, home, end, etc.)\n- Vertical and horizontal orientation\n- Typeahead to allow focusing the matching item\n- Supports items, labels, groups of items\n- Supports grid and list layouts\n\n## Installation\n\nInstall the listbox package:\n\n```bash\nnpm install @zag-js/listbox @zag-js/svelte\n# or\nyarn add @zag-js/listbox @zag-js/svelte\n```\n\n## Anatomy\n\nCheck the listbox anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the listbox package:\n\n```tsx\nimport * as listbox from \"@zag-js/listbox\"\n```\n\nThe listbox package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\n> Pass a unique `id` to `useMachine` so generated element ids stay predictable.\n\nThen use the framework integration helpers:\n\n```svelte\n<script lang=\"ts\">\n  import * as listbox from \"@zag-js/listbox\"\n  import { normalizeProps, useMachine } from \"@zag-js/svelte\"\n  import { createUniqueId } from \"@zag-js/utils\"\n\n  const data = [\n    { label: \"Nigeria\", value: \"NG\" },\n    { label: \"United States\", value: \"US\" },\n    { label: \"Canada\", value: \"CA\" },\n    { label: \"Japan\", value: \"JP\" },\n  ]\n\n  const collection = listbox.collection({ items: data })\n\n  const service = useMachine(listbox.machine, {\n    id: createUniqueId(),\n    collection,\n  })\n\n  const api = $derived(listbox.connect(service, normalizeProps))\n</script>\n\n<div {...api.getRootProps()}>\n  <label {...api.getLabelProps()}>Select country</label>\n  <ul {...api.getContentProps()}>\n    {#each data as item}\n      <li {...api.getItemProps({ item })}>\n        <span {...api.getItemTextProps({ item })}>{item.label}</span>\n        <span {...api.getItemIndicatorProps({ item })}>✓</span>\n      </li>\n    {/each}\n  </ul>\n</div>\n```\n\n### Setting the initial selection\n\nTo set the initial selection, you can use the `defaultValue` property.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  // ...\n  defaultValue: [\"item-1\", \"item-2\"],\n})\n```\n\n### Controlling the selection\n\nUse `value` and `onValueChange` to control selection externally.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  value: [\"item-1\", \"item-2\"],\n  onValueChange(details) {\n    // details => { value: string[]; items: CollectionItem[] }\n    console.log(details.value)\n  },\n})\n```\n\n### Controlling the highlighted item\n\nUse `highlightedValue` and `onHighlightChange` to control highlighted state.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  highlightedValue,\n  onHighlightChange(details) {\n    // details => { highlightedValue: string | null, highlightedItem, highlightedIndex }\n    setHighlightedValue(details.highlightedValue)\n  },\n})\n```\n\n### Filtering\n\nThe listbox component supports filtering of items via `api.getInputProps`.\nHere's an example of how to support searching through a list of items.\n\n```svelte\n<script lang=\"ts\">\n  import * as listbox from \"@zag-js/listbox\"\n  import { createFilter } from \"@zag-js/i18n-utils\"\n  import { normalizeProps, useMachine } from \"@zag-js/svelte\"\n\n  interface Item {\n    label: string\n    value: string\n  }\n\n  const data: Item[] = [\n    { label: \"Nigeria\", value: \"NG\" },\n    { label: \"United States\", value: \"US\" },\n    { label: \"Canada\", value: \"CA\" },\n    { label: \"Japan\", value: \"JP\" },\n  ]\n\n  const filter = createFilter({ sensitivity: \"base\" })\n\n  let search = $state(\"\")\n\n  const collection = $derived.by(() => {\n    const items = data.filter((item) => filter.startsWith(item.label, search))\n    return listbox.collection({ items })\n  })\n\n  const id = $props.id()\n\n  const service = useMachine(listbox.machine as listbox.Machine<Item>, {\n    id,\n    get collection() {\n      return collection\n    },\n    typeahead: false,\n  })\n\n  const api = $derived(listbox.connect(service, normalizeProps))\n</script>\n\n<div {...api.getRootProps()}>\n  <input\n    {...api.getInputProps({ autoHighlight: true })}\n    bind:value={search}\n  />\n  <ul {...api.getContentProps()}>\n    {#each collection.items as item (item.value)}\n      <li {...api.getItemProps({ item })}>\n        <span {...api.getItemTextProps({ item })}>{item.label}</span>\n        <span {...api.getItemIndicatorProps({ item })}>✓</span>\n      </li>\n    {/each}\n  </ul>\n</div>\n```\n\n### Selecting multiple items\n\nTo enable multiple selection, set the `selectionMode` property to `multiple` or\n`extended`.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  // ...\n  selectionMode: \"multiple\",\n})\n```\n\n### Selection Modes\n\nUse `selectionMode` to control selection behavior:\n\n- **single**: A user can select a single item using the space bar, mouse click,\n  or touch tap.\n- **multiple**: A user can select multiple items using the space bar, mouse\n  click, or touch tap to toggle selection on the focused item. Using the arrow\n  keys, a user can move focus independently of selection.\n- **extended**: With no modifier keys like `Ctrl`, `Cmd` or `Shift`: the\n  behavior is the same as single selection.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  // ...\n  selectionMode: \"extended\",\n})\n```\n\n### Selecting on highlight\n\nSet `selectOnHighlight` to `true` to select items as they become highlighted.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  selectOnHighlight: true,\n})\n```\n\n### Disallowing select-all shortcuts\n\nSet `disallowSelectAll` to disable `Cmd/Ctrl + A` selection.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  selectionMode: \"multiple\",\n  disallowSelectAll: true,\n})\n```\n\n### Listening for item selection\n\nUse `onSelect` to react whenever an item is selected.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  onSelect(details) {\n    // details => { value: string }\n    console.log(details.value)\n  },\n})\n```\n\n### Disabling items\n\nTo disable an item, you can use the `disabled` property.\n\n```tsx\napi.getItemProps({\n  // ...\n  disabled: true,\n})\n```\n\nTo disable the entire listbox, you can use the `disabled` property.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  disabled: true,\n})\n```\n\n### Grid layout\n\nTo enable a grid layout, provide a grid collection to the `collection` property.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  collection: listbox.gridCollection({\n    items: [],\n    columnCount: 3,\n  }),\n})\n```\n\n```svelte\n<script lang=\"ts\">\n  import * as listbox from \"@zag-js/listbox\"\n  import { normalizeProps, useMachine } from \"@zag-js/svelte\"\n  import { createUniqueId } from \"@zag-js/utils\"\n\n  const data = [\n    { label: \"Red\", value: \"red\" },\n    { label: \"Green\", value: \"green\" },\n    { label: \"Blue\", value: \"blue\" },\n    { label: \"Yellow\", value: \"yellow\" },\n    { label: \"Purple\", value: \"purple\" },\n    { label: \"Orange\", value: \"orange\" },\n  ]\n\n  const collection = listbox.gridCollection({\n    items: data,\n    columnCount: 3,\n  })\n\n  const service = useMachine(listbox.machine, {\n    id: createUniqueId(),\n    collection,\n  })\n\n  const api = $derived(listbox.connect(service, normalizeProps))\n</script>\n\n<div {...api.getRootProps()}>\n  <label {...api.getLabelProps()}>Select color</label>\n  <div\n    {...api.getContentProps()}\n    style=\"display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px\"\n  >\n    {#each data as item}\n      <div {...api.getItemProps({ item })}>\n        <span {...api.getItemTextProps({ item })}>{item.label}</span>\n        <span {...api.getItemIndicatorProps({ item })}>✓</span>\n      </div>\n    {/each}\n  </div>\n</div>\n```\n\n### Horizontal orientation\n\nSet `orientation` to `horizontal` for horizontal keyboard navigation.\n\n```tsx\nconst service = useMachine(listbox.machine, {\n  orientation: \"horizontal\",\n  collection,\n})\n```\n\n## Styling guide\n\nEach part includes a `data-part` attribute you can target in CSS.\n\n```css\n[data-scope=\"listbox\"][data-part=\"root\"] {\n  /* styles for the root part */\n}\n\n[data-scope=\"listbox\"][data-part=\"label\"] {\n  /* styles for the label part */\n}\n\n[data-scope=\"listbox\"][data-part=\"content\"] {\n  /* styles for the content part */\n}\n\n[data-scope=\"listbox\"][data-part=\"item\"] {\n  /* styles for the item part */\n}\n\n[data-scope=\"listbox\"][data-part=\"itemGroup\"] {\n  /* styles for the item group part */\n}\n```\n\n### Focused state\n\nThe focused state is applied to the item that is currently focused.\n\n```css\n[data-scope=\"listbox\"][data-part=\"item\"][data-focused] {\n  /* styles for the focused item part */\n}\n```\n\n### Selected state\n\nThe selected state is applied to the item that is currently selected.\n\n```css\n[data-scope=\"listbox\"][data-part=\"item\"][data-selected] {\n  /* styles for the selected item part */\n}\n```\n\n### Disabled state\n\nThe disabled state is applied to the item that is currently disabled.\n\n```css\n[data-scope=\"listbox\"][data-part=\"item\"][data-disabled] {\n  /* styles for the disabled item part */\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe listbox machine exposes the following context properties:\n\n**`orientation`**\nType: `\"horizontal\" | \"vertical\"`\nDescription: The orientation of the listbox.\n\n**`collection`**\nType: `GridCollection<T>`\nDescription: The item collection\n\n**`ids`**\nType: `Partial<{ root: string; content: string; label: string; item: (id: string | number) => string; itemGroup: (id: string | number) => string; itemGroupLabel: (id: string | number) => string; }>`\nDescription: The ids of the elements in the listbox. Useful for composition.\n\n**`disabled`**\nType: `boolean`\nDescription: Whether the listbox is disabled\n\n**`disallowSelectAll`**\nType: `boolean`\nDescription: Whether to disallow selecting all items when `meta+a` is pressed\n\n**`onHighlightChange`**\nType: `(details: HighlightChangeDetails<T>) => void`\nDescription: The callback fired when the highlighted item changes.\n\n**`onValueChange`**\nType: `(details: ValueChangeDetails<T>) => void`\nDescription: The callback fired when the selected item changes.\n\n**`value`**\nType: `string[]`\nDescription: The controlled keys of the selected items\n\n**`defaultValue`**\nType: `string[]`\nDescription: The initial default value of the listbox when rendered.\nUse when you don't need to control the value of the listbox.\n\n**`highlightedValue`**\nType: `string`\nDescription: The controlled key of the highlighted item\n\n**`defaultHighlightedValue`**\nType: `string`\nDescription: The initial value of the highlighted item when opened.\nUse when you don't need to control the highlighted value of the listbox.\n\n**`loopFocus`**\nType: `boolean`\nDescription: Whether to loop the keyboard navigation through the options\n\n**`selectionMode`**\nType: `SelectionMode`\nDescription: How multiple selection should behave in the listbox.\n\n- `single`: The user can select a single item.\n- `multiple`: The user can select multiple items without using modifier keys.\n- `extended`: The user can select multiple items by using modifier keys.\n\n**`scrollToIndexFn`**\nType: `(details: ScrollToIndexDetails) => void`\nDescription: Function to scroll to a specific index\n\n**`selectOnHighlight`**\nType: `boolean`\nDescription: Whether to select the item when it is highlighted\n\n**`deselectable`**\nType: `boolean`\nDescription: Whether to disallow empty selection\n\n**`typeahead`**\nType: `boolean`\nDescription: Whether to enable typeahead on the listbox\n\n**`onSelect`**\nType: `(details: SelectionDetails) => void`\nDescription: Function called when an item is selected\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe listbox `api` exposes the following methods:\n\n**`empty`**\nType: `boolean`\nDescription: Whether the select value is empty\n\n**`highlightedValue`**\nType: `string`\nDescription: The value of the highlighted item\n\n**`highlightedItem`**\nType: `V`\nDescription: The highlighted item\n\n**`highlightValue`**\nType: `(value: string) => void`\nDescription: Function to highlight a value\n\n**`highlightFirst`**\nType: `VoidFunction`\nDescription: Function to highlight the first value\n\n**`highlightLast`**\nType: `VoidFunction`\nDescription: Function to highlight the last value\n\n**`highlightNext`**\nType: `VoidFunction`\nDescription: Function to highlight the next value\n\n**`highlightPrevious`**\nType: `VoidFunction`\nDescription: Function to highlight the previous value\n\n**`clearHighlightedValue`**\nType: `VoidFunction`\nDescription: Function to clear the highlighted value\n\n**`selectedItems`**\nType: `V[]`\nDescription: The selected items\n\n**`hasSelectedItems`**\nType: `boolean`\nDescription: Whether there's a selected option\n\n**`value`**\nType: `string[]`\nDescription: The selected item keys\n\n**`valueAsString`**\nType: `string`\nDescription: The string representation of the selected items\n\n**`selectValue`**\nType: `(value: string) => void`\nDescription: Function to select a value\n\n**`selectAll`**\nType: `VoidFunction`\nDescription: Function to select all values.\n\n**Note**: This should only be called when the selectionMode is `multiple` or `extended`.\nOtherwise, an exception will be thrown.\n\n**`setValue`**\nType: `(value: string[]) => void`\nDescription: Function to set the value of the select\n\n**`clearValue`**\nType: `(value?: string) => void`\nDescription: Function to clear the value of the select.\nIf a value is provided, it will only clear that value, otherwise, it will clear all values.\n\n**`getItemState`**\nType: `(props: ItemProps<any>) => ItemState`\nDescription: Returns the state of a select item\n\n**`collection`**\nType: `ListCollection<V>`\nDescription: Function to toggle the select\n\n**`disabled`**\nType: `boolean`\nDescription: Whether the select is disabled\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: listbox\n**`data-part`**: root\n**`data-orientation`**: The orientation of the listbox\n**`data-disabled`**: Present when disabled\n\n**`Input`**\n\n**`data-scope`**: listbox\n**`data-part`**: input\n**`data-disabled`**: Present when disabled\n\n**`Label`**\n\n**`data-scope`**: listbox\n**`data-part`**: label\n**`data-disabled`**: Present when disabled\n\n**`ValueText`**\n\n**`data-scope`**: listbox\n**`data-part`**: value-text\n**`data-disabled`**: Present when disabled\n\n**`Item`**\n\n**`data-scope`**: listbox\n**`data-part`**: item\n**`data-value`**: The value of the item\n**`data-selected`**: Present when selected\n**`data-layout`**: \n**`data-state`**: \"checked\" | \"unchecked\"\n**`data-orientation`**: The orientation of the item\n**`data-highlighted`**: Present when highlighted\n**`data-disabled`**: Present when disabled\n\n**`ItemText`**\n\n**`data-scope`**: listbox\n**`data-part`**: item-text\n**`data-state`**: \"checked\" | \"unchecked\"\n**`data-disabled`**: Present when disabled\n**`data-highlighted`**: Present when highlighted\n\n**`ItemIndicator`**\n\n**`data-scope`**: listbox\n**`data-part`**: item-indicator\n**`data-state`**: \"checked\" | \"unchecked\"\n\n**`ItemGroup`**\n\n**`data-scope`**: listbox\n**`data-part`**: item-group\n**`data-disabled`**: Present when disabled\n**`data-orientation`**: The orientation of the item\n**`data-empty`**: Present when the content is empty\n\n**`Content`**\n\n**`data-scope`**: listbox\n**`data-part`**: content\n**`data-activedescendant`**: The id the active descendant of the content\n**`data-orientation`**: The orientation of the content\n**`data-layout`**: \n**`data-empty`**: Present when the content is empty\n\n### CSS Variables\n\n<CssVarTable name=\"listbox\" />\n\n## Accessibility\n\nAdheres to the\n[Listbox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/).","package":"@zag-js/listbox","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/listbox.mdx"}