Listbox 
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot } from 'radix-vue'
const fruits = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple']
const vegetables = ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
</script>
<template>
  <ListboxRoot class=" flex flex-col rounded-lg border bg-white text-green9 mx-auto ">
    <ListboxContent class="p-[5px] w-48 h-72 overflow-auto">
      <ListboxGroup>
        <ListboxGroupLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
          Fruits
        </ListboxGroupLabel>
        <ListboxItem
          v-for="i in fruits"
          :key="i"
          :value="i"
          class="w-full flex items-center px-[25px] h-[25px] leading-none text-[13px] relative text-green9 select-none outline-none data-[highlighted]:ring-green9 data-[highlighted]:ring-1 focus:ring-green9 focus:ring-1  data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
        >
          <ListboxItemIndicator
            class="absolute left-0 w-[25px] inline-flex items-center justify-center"
          >
            <Icon icon="radix-icons:check" />
          </ListboxItemIndicator>
          <span>{{ i }}</span>
        </ListboxItem>
      </ListboxGroup>
      <ListboxGroup class="mt-2">
        <ListboxGroupLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
          Vegetables
        </ListboxGroupLabel>
        <ListboxItem
          v-for="i in vegetables"
          :key="i"
          :value="i"
          class="w-full flex items-center px-[25px] h-[25px] leading-none text-[13px] relative text-green9 select-none outline-none data-[highlighted]:ring-green9 data-[highlighted]:ring-1 focus:ring-green9 focus:ring-1  data-[state=checked]:bg-green9 data-[state=checked]:text-white data-[disabled]:opacity-50 rounded"
        >
          <ListboxItemIndicator
            class="absolute left-0 w-[25px] inline-flex items-center justify-center"
          >
            <Icon icon="radix-icons:check" />
          </ListboxItemIndicator>
          <span>{{ i }}</span>
        </ListboxItem>
      </ListboxGroup>
    </ListboxContent>
  </ListboxRoot>
</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.
$ npm add radix-vueAnatomy 
Import all parts and piece them together.
<script setup>
import { ListboxContent, ListboxFilter, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, ListboxRoot, ListboxVirtualizer } from 'radix-vue'
</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.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our 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.  | |
| disabled | booleanWhen  | |
| highlightOnHover | booleanWhen  | |
| modelValue | AcceptableValue | AcceptableValue[]The controlled value of the listbox. Can be binded-with with  | |
| multiple | booleanWhether multiple options can be selected or not. | |
| name | stringThe name of the listbox. Submitted with its owning form as part of a name/value pair. | |
| orientation | 'vertical' | 'vertical' | 'horizontal'The orientation of the listbox.  | 
| selectionBehavior | 'toggle' | 'toggle' | 'replace'How multiple selection should behave in the collection. | 
| Emit | Payload | 
|---|---|
| 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 (default) | Payload | 
|---|---|
| modelValue | AcceptableValue | AcceptableValue[] | undefinedCurrent active value | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
Filter 
Input element to perform filtering.
| Prop | Default | Type | 
|---|---|---|
| as | 'input' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
| autoFocus | booleanFocus on element when mounted. | |
| modelValue | stringThe controlled value of the filter. Can be binded-with with v-model. | 
| Emit | Payload | 
|---|---|
| update:modelValue | [string]Event handler called when the value changes. | 
| Slots (default) | Payload | 
|---|---|
| modelValue | string | undefinedCurrent input values | 
| Data Attribute | Value | 
|---|---|
| [data-disabled] | Present when disabled | 
Content 
Contains all the listbox group and items.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
Item 
The item component.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
| disabled | booleanWhen  | |
| value* | AcceptableValueThe value given as data when submitted with a  | 
| Emit | Payload | 
|---|---|
| select | [event: SelectEvent<AcceptableValue>]Event handler called when the selecting item.  | 
| 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.
| Prop | Default | Type | 
|---|---|---|
| as | 'span' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
Group 
Used to group multiple items. use in conjunction with ListboxGroupLabel to ensure good accessibility via automatic labelling.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | 
GroupLabel 
Used to render the label of a group. It won't be focusable using arrow keys.
| Prop | Default | Type | 
|---|---|---|
| as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by  | 
| asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
| for | string | 
Virtualizer 
Virtual container to achieve list virtualization.
| Prop | Default | Type | 
|---|---|---|
| estimateSize | numberEstimated size (in px) of each item | |
| options* | AcceptableValue[]List of items | |
| textContent | ((option: AcceptableValue) => string)text content for each item to achieve type-ahead feature | 
| Slots (default) | Payload | 
|---|---|
| option | string | number | false | true | Record<string, any> | 
Examples 
Binding objects as values 
Unlike native HTML form controls which only allow you to provide strings as values, radix-vue supports binding complex objects as well.
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'radix-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 { ref } from 'vue'
import { ListboxRoot } from 'radix-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 { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot } from 'radix-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 filteredPeople = computed(() =>
  searchTerm.value === ''
    ? people
    : people.filter((person) => {
      return person.name.toLowerCase().includes(searchTerm.value.toLowerCase())
    })
)
</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.
<script setup lang="ts">
import { ref } from 'vue'
import { ListboxContent, ListboxFilter, ListboxItem, ListboxRoot, ListboxVirtualizer } from 'radix-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>
      <!-- checkout https://radix-vue.com/components/listbox.html#virtualizer -->
      <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. |