Skip to content

Listbox

Searchable, keyboard-navigable list. Built on reka-ui's Listbox with aurora's automatic filtering on top.

Unlike Combobox, this is not a form element — it's a standalone filterable list you compose into popovers, sidebars, or any container. Use it when you want filtering + keyboard nav without the form-input chrome.

The four pieces:

  • Listbox — root, manages selection and provides filter context
  • ListboxInput — search field, auto-filters items by their text content
  • ListboxContent — scrollable container for items
  • ListboxItem — selectable item; self-registers its text for filtering
  • ListboxEmpty — renders when the search matches nothing

Basic

Apple
Banana
Cherry
Durian
Elderberry
Fig
Grape
Honeydew
Kiwi
Lemon
Mango
html
<Listbox v-model="selected">
  <ListboxInput placeholder="Search…" />
  <ListboxContent>
    <ListboxItem v-for="f in fruits" :key="f" :value="f.toLowerCase()">
      {{ f }}
    </ListboxItem>
    <ListboxEmpty>No matches</ListboxEmpty>
  </ListboxContent>
</Listbox>

Custom item content

ListboxItem accepts arbitrary slot content. Filtering uses each item's rendered text — composite items still match against everything inside.

United StatesUS
United KingdomGB
GermanyDE
FranceFR
JapanJP
BrazilBR
AustraliaAU
html
<Listbox v-model="country">
  <ListboxInput placeholder="Search countries…" />
  <ListboxContent>
    <ListboxItem v-for="c in countries" :key="c.value" :value="c.value">
      <span class="truncate">{{ c.label }}</span>
      <span class="ml-auto text-secondary paragraph-2xs">{{ c.value.toUpperCase() }}</span>
    </ListboxItem>
    <ListboxEmpty>No countries found</ListboxEmpty>
  </ListboxContent>
</Listbox>

Inside a Popper (dropdown pattern)

Listbox + Popper is the canonical way to build a click-to-open searchable picker without using Combobox (which is a form input).

html
<Popper v-model:is-open="isOpen" placement="bottom-start">
  <PopperTrigger>
    <Tag clickable outline>{{ selected || 'Pick one' }}</Tag>
  </PopperTrigger>
  <PopperContent>
    <div class="w-72 rounded-2 border border-primary bg-white shadow-300 overflow-hidden">
      <Listbox v-model="selected">
        <ListboxInput placeholder="Search…" />
        <ListboxContent>
          <ListboxItem v-for="item in items" :key="item" :value="item">
            {{ item }}
          </ListboxItem>
          <ListboxEmpty>No results</ListboxEmpty>
        </ListboxContent>
      </Listbox>
    </div>
  </PopperContent>
</Popper>

Listbox — Props

Listbox extends reka-ui's ListboxRoot — every prop documented there is accepted. Most-used:

PropTypeDefaultDescription
modelValuestring | string[]''Selected value(s). Use v-model.
multiplebooleanfalseAllow multi-selection (modelValue becomes an array).
disabledbooleanfalseDisable the entire listbox.
classstringAdditional classes for the root.

ListboxInput

Search input with auto-focus on mount. Text typed here filters the items in real time (case-insensitive substring match against each item's rendered text).

PropTypeDefaultDescription
classstringAdditional classes.

Also forwards reka-ui's ListboxFilterProps.

ListboxContent

Scrollable container for the items. Add max-h-* and overflow-auto (or use the default styling) to constrain long lists.

ListboxItem

PropTypeDefaultDescription
valueAcceptableValuerequiredItem value used by v-model.
disabledbooleanfalseDisable selection.
classstringAdditional classes.

Items hide automatically when their rendered text doesn't match the current search term.

ListboxEmpty

Renders only when the user has typed something and zero items match. Slot content is whatever you want to display.

html
<ListboxEmpty>No results</ListboxEmpty>