Listbox
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.
$ npm add reka-uiAnatomy
Import all parts and piece them together.
<script setup>
import { ListboxContent, ListboxFilter, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot, ListboxVirtualizer } from 'reka-ui'
</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.
| Data Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Filter
Input element to perform filtering.
| Data Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Content
Contains all the listbox group and items.
Item
The item component.
| 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.
Group
Used to group multiple items. use in conjunction with ListboxGroupLabel to ensure good accessibility via automatic labelling.
GroupLabel
Used to render the label of a group. It won't be focusable using arrow keys.
Virtualizer
Virtual container to achieve list virtualization.
Examples
Binding objects as values
Unlike native HTML form controls which only allow you to provide strings as values, reka-ui supports binding complex objects as well.
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'reka-ui'
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.
<script setup lang="ts">
import { ListboxRoot } from 'reka-ui'
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
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, useFilter } from 'reka-ui'
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 for more general info on virtualization.
<script setup lang="ts">
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, ListboxVirtualizer } from 'reka-ui'
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.
Keyboard Interactions
| Key | Description |
|---|---|
Enter | When highlight on ListboxItem, selects the focused item. |
ArrowDown | When focus is on ListboxItem, moves focus to the next item. |
ArrowUp | When focus is on ListboxItem, moves focus to the previous item. |
Home | Moves focus and highlight to the first item. |
End | Moves focus and highlight to the last item. |
Ctrl/Cmd + A | Select all the items. |
