---
title: "Listbox"
description: "A control that allows the user to toggle between checked and not checked."
canonical_url: "https://vinicunca.dev/akar/components/listbox"
---
# Listbox

> A control that allows the user to toggle between checked and not checked.

```vue [index.vue]
<script setup lang="ts">
import { ListboxContent, ListboxItem, ListboxRoot } from 'akar'
</script>

<template>
  <div class="akar-demo akar-demo-Listbox">
    <ListboxRoot class="w-48 h-72 flex flex-col p-1 rounded-lg border bg-white text-green9 mx-auto overflow-auto">
        <ListboxContent>
          <ListboxItem
            v-for="i in 20"
            :key="i"
            :value="i"
            class="w-full py-1 px-2 text-green9 select-none text-sm focus:ring-0 data-[highlighted]:outline-green9 data-[highlighted]:outline-1 data-[highlighted]:outline focus:outline-green9 data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
          >
            {{ i }}
          </ListboxItem>
        </ListboxContent>
      </ListboxRoot>
  </div>
</template>
```

## Features

- Can be controlled or uncontrolled.
- Supports items, labels, groups of items.
- Focus is fully managed.
- Full keyboard navigation.
- Supports Right to Left direction.
- Different selection behavior.

## Installation

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import all parts and piece them together.

```vue
<script setup>
import { ListboxContent, ListboxFilter, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot, ListboxVirtualizer } from 'akar';
</script>

<template>
  <ListboxRoot>
    <ListboxFilter />

    <ListboxContent>
      <ListboxItem>
        <ListboxItemIndicator />
      </ListboxItem>

      <!-- or with group -->
      <ListboxGroup>
        <ListboxGroupLabel />
        <ListboxItem>
          <ListboxItemIndicator />
        </ListboxItem>
      </ListboxGroup>

      <!-- or with virtual -->
      <ListboxVirtualizer>
        <ListboxItem>
          <ListboxItemIndicator />
        </ListboxItem>
      </ListboxVirtualizer>
    </ListboxContent>
  </ListboxRoot>
</template>
```

## API Reference

### Root

Contains all the parts of a listbox. An `input` will also render when used within a `form` to ensure events propagate correctly.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `by` |  | `string \| ((a: AcceptableValue, b: AcceptableValue) => boolean)` | Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared. |
| `defaultValue` |  | `AcceptableValue \| AcceptableValue[]` | The value of the listbox when initially rendered. Use when you do not need to control the state of the Listbox |
| `dir` |  | `"ltr" \| "rtl"` | The reading direction of the listbox when applicable.<br><br>If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `disabled` |  | `boolean` | When `true`, prevents the user from interacting with listbox |
| `highlightOnHover` |  | `boolean` | When `true`, hover over item will trigger highlight |
| `modelValue` |  | `AcceptableValue \| AcceptableValue[]` | The controlled value of the listbox. Can be binded with `v-model`. |
| `multiple` |  | `boolean` | Whether multiple options can be selected or not. |
| `name` |  | `string` | The name of the field. Submitted with its owning form as part of a name/value pair. |
| `orientation` | `"vertical"` | `"vertical" \| "horizontal"` | The orientation of the listbox.<br><br>Mainly so arrow navigation is done accordingly (left & right vs. up & down) |
| `required` |  | `boolean` | When `true`, indicates that the user must set the value before the owning form can be submitted. |
| `selectionBehavior` | `"toggle"` | `"replace" \| "toggle"` | How multiple selection should behave in the collection. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `entryFocus` | `event: CustomEvent<any>` | Event handler called when container is being focused. Can be prevented. |
| `highlight` | `payload: { ref: HTMLElement; value: AcceptableValue; }` | Event handler when highlighted element changes. |
| `leave` | `event: Event` | Event handler called when the mouse leave the container |
| `update:modelValue` | `value: AcceptableValue` | Event handler called when the value changes. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `modelValue` | `T \| T[]` | Current active value |

[ListboxRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxRoot.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Filter

Input element to perform filtering.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"input"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `autoFocus` |  | `boolean` | Focus on element when mounted. |
| `disabled` |  | `boolean` | When `true`, prevents the user from interacting with item |
| `modelValue` |  | `string` | The controlled value of the filter. Can be binded with v-model. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `string` |  |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `modelValue` | `string` | Current input values |

[ListboxFilter.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxFilter.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Content

Contains all the listbox group and items.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ListboxContent.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxContent.vue)

### Item

The item component.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `disabled` |  | `boolean` | When `true`, prevents the user from interacting with the item. |
| `value*` |  | `T` | The value given as data when submitted with a `name`. |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `select` | `event: SelectEvent<T>` | Event handler called when the selecting item.<br><br>It can be prevented by calling `event.preventDefault`. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `selected` | `boolean` | Whether the item is currently selected |

[ListboxItem.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxItem.vue)

| Data attribute | Value |
| --- | --- |
| `[data-state]` | "checked" \\| "unchecked" |
| `[data-highlighted]` | Present when highlighted |
| `[data-disabled]` | Present when disabled |

### ItemIndicator

Renders when the item is selected. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"span"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `forceMount` |  | `boolean` | Used to force mounting when more control is needed. Useful when<br>controlling animation with Vue animation libraries. |

[ListboxItemIndicator.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxItemIndicator.vue)

### Group

Used to group multiple items. use in conjunction with `ListboxGroupLabel` to ensure good accessibility via automatic labelling.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |

[ListboxGroup.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxGroup.vue)

### GroupLabel

Used to render the label of a group. It won't be focusable using arrow keys.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://vinicunca.dev/akar/guides/composition) guide for more details. |
| `for` |  | `string` |  |

[ListboxGroupLabel.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxGroupLabel.vue)

### Virtualizer

Virtual container to achieve list virtualization.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `estimateSize` |  | `number \| ((index: number) => number)` | Estimated size (in px) of each item |
| `options*` |  | `T` | List of items |
| `overscan` |  | `number` | Number of items rendered outside the visible area |
| `textContent` |  | `((option: T) => string)` | Text content for each item to achieve type-ahead feature |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `option` | `T` |  |
| `virtualizer` | `Virtualizer<HTMLElement, Element>` |  |
| `virtualItem` | `VirtualItem` |  |

[ListboxVirtualizer.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox/ListboxVirtualizer.vue)

## Examples

### Binding objects as values

Unlike native HTML form controls which only allow you to provide strings as values, Akar supports binding complex objects as well.

```vue
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'akar'
import { ref } from 'vue'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref(people[0])
</script>

<template>
  <ListboxRoot v-model="selectedPeople">
    <ListboxContent>
      <ListboxItem
        v-for="person in people"
        :key="person.id"
        :value="person"
        :disabled="person.unavailable"
      >
        {{ person.name }}
      </ListboxItem>
    </ListboxContent>
  </ListboxRoot>
</template>
```

### Selecting multiple values

The `Listbox` component allows you to select multiple values. You can enable this by providing an array of values instead of a single value.

```vue
<script setup lang="ts">
import { ListboxRoot } from 'akar'
import { ref } from 'vue'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref([people[0], people[1]])
</script>

<template>
  <ListboxRoot
    v-model="selectedPeople"
    multiple
  >
    ...
  </ListboxRoot>
</template>
```

### Custom filtering

```vue
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, useFilter } from 'akar'
import { ref } from 'vue'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref(people[0])
const searchTerm = ref('')

const { startsWith } = useFilter({ sensitivity: 'base' })
const filteredPeople = computed(() => people.filter(p => startsWith(p.name, searchTerm.value)))
</script>

<template>
  <ListboxRoot v-model="selectedPeople">
    <ListboxFilter v-model="searchTerm" />
    <ListboxContent>
      <ListboxItem
        v-for="person in filteredPeople"
        :key="person.id"
        :value="person"
      >
        {{ person.name }}
      </ListboxItem>
    </ListboxContent>
  </ListboxRoot>
</template>
```

### Virtual List

Rendering a long list of item can slow down the app, thus using virtualization would significantly improve the performance.

See the [virtualization guide](https://vinicunca.dev/akar/guides/virtualization.md) for more general info on virtualization.

```vue
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, ListboxVirtualizer } from 'akar'
import { ref } from 'vue'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
  // and a lot more
]
</script>

<template>
  <ListboxRoot>
    <ListboxContent>
      <ListboxVirtualizer
        v-slot="{ option }"
        :options="people"
        :text-content="(opt) => opt.name"
      >
        <ListboxItem :value="option">
          {{ person.name }}
        </ListboxItem>
      </ListboxVirtualizer>
    </ListboxContent>
  </ListboxRoot>
</template>
```

## Accessibility

Adheres to the [Listbox WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/).

### Keyboard Interactions

| Key | Description |
| --- | --- |
| <kbd>Enter</kbd> | When highlight on `ListboxItem`, selects the focused item.  |
| <kbd>ArrowDown</kbd> | When focus is on `ListboxItem`, moves focus to the next item.  |
| <kbd>ArrowUp</kbd> | When focus is on `ListboxItem`, moves focus to the previous item.  |
| <kbd>Home</kbd> | Moves focus and highlight to the first item. |
| <kbd>End</kbd> | Moves focus and highlight to the last item. |
| <kbd>Ctrl/Cmd + A</kbd> | Select all the items. |

---

- [ARIA](https://www.w3.org/WAI/ARIA/apg/patterns/listbox)
- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Listbox)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
