Combobox
Combobox combines a text input with a role="listbox" popup. Users type to filter options, move through suggestions with the keyboard, and select from a known set. Use Select when no text input is needed.
Popup placement flips when preferred side lacks room, clamps to viewport, and follows anchor/content resize and ancestor scrolling.
Anatomy
#option: Custom selectable option row content.#[option.slot]: Per-option render override.#tag: Selected tag content in multiple mode.#clear: Clear-button content.#create: Creatable row content.#group-label: Custom label row content.#empty: Empty state when filtering returns no selectable options.#loading: Loading state content.
The input, hidden form input, listbox, viewport, options, indicators, separators, and state attrs are generated by the component.
Usage
Value: vue
Examples
Controlled search
Bind v-model:search when search text must drive async loading or external filtering.
<script setup lang="ts">
const value = ref("");
const search = ref("");
</script>
<template>
<Combobox v-model="value" v-model:search="search" :options="options" />
</template>
Multiple values
Set multiple and bind v-model to an array. clearable adds a clear control; selected values expose removable tags.
<template>
<Combobox v-model="skills" multiple clearable :options="skillOptions" />
</template>
Custom filtering
Use filter when option search should use aliases, tags, or server-shaped data.
<template>
<Combobox
v-model="value"
:options="options"
:filter="(option, search) => String(option.keywords).includes(search)"
/>
</template>
Field integration
Place Combobox inside Field to inherit label metadata and form state.
<template>
<Field label="Stack" name="stack" required>
<Combobox v-model="stack" :options="options" />
</Field>
</template>
Creatable options
Creation is app-controlled: Akaza emits requested text and your app decides whether and how to add it.
<Combobox
v-model="framework"
creatable
:options="options"
@create="value => options.push({ value, label: value })"
/>
Object values
Object values use identity by default. Supply isEqual when values are recreated and serializeValue when submitting them in a form.
<Combobox
v-model="assignee"
name="assignee"
:options="people"
:is-equal="(a, b) => a.id === b.id"
:serialize-value="value => String(value.id)"
/>
Read-only and loading
readOnly preserves a visible value without allowing changes. loading exposes aria-busy and the loading slot for async sources.
<Combobox v-model="value" read-only :options="options" />
<Combobox v-model="value" loading :options="remoteOptions">
<template #loading>Fetching teams…</template>
</Combobox>
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | ComboboxOption[] | required | Options rendered in the listbox. |
valueKey | string | — | Object key used as option value. |
labelKey | string | "label" | Object key used as option label. |
descriptionKey | string | "description" | Object key used as description. |
disabledKey | string | "disabled" | Object key used as disabled state. |
placeholder | string | — | Input placeholder. |
multiple | boolean | false | Enables multi-select. |
nullableValue | string | "" | Submitted empty value. |
id | string | field id | Input id. |
name | string | field name | Form field name for hidden selected values. |
required | boolean | false | Required state. |
disabled | boolean | false | Disables input and options. |
readOnly | boolean | false | Keeps value readable but prevents opening, search, and selection changes. |
invalid | boolean | false | Sets invalid attrs. |
loop | boolean | true | Arrow navigation wraps. |
filterable | boolean | true | Enables client filtering and aria-autocomplete="list". |
filter | (option, search) => boolean | label contains search | Custom filter. |
isEqual | (a, b) => boolean | Object.is | Value comparator, useful for recreated object values. |
serializeValue | (value) => string | string/JSON | Serializes values for native form submission. |
loading | boolean | false | Shows loading slot. |
emptyLabel | string | "No results found." | Default empty text. |
resetSearchOnBlur | boolean | false | Clears search on blur. |
resetSearchOnSelect | boolean | true | Clears search after selection. |
openOnFocus | boolean | true | Opens when input receives focus. |
openOnClick | boolean | true | Opens when input is clicked. |
openOnInput | boolean | true | Opens when search text changes. |
clearable | boolean | false | Renders clear button when filled. |
creatable | boolean | false | Shows create row for unmatched search. |
createLabel | (search) => string | Create “…” | Formats default create row. |
highlightOnHover | boolean | true | Pointer hover updates highlight. |
side | "top" | "bottom" | "bottom" | Popup side. |
align | "start" | "center" | "end" | "start" | Popup alignment. |
sideOffset | number | 6 | Popup gap in pixels. |
ariaLabel | string | — | Accessible label. |
ariaLabelledby | string | — | Accessible label id. |
ariaDescribedby | string | field description/error | Description ids. |
ui | ComboboxUi | — | Classes for structural parts. |
Emits
| Event | Payload | Description |
|---|---|---|
open-change | (open, details) | Fired before popup opens/closes. |
value-change | (value, details) | Fired before selected value changes. |
search-change | (value, details) | Fired before search text changes. |
create | (search, details) | Requests creation of unmatched search text. |
Slots
| Slot | Props | Description |
|---|---|---|
option | option, value, label, description, isSelected, isHighlighted, isDisabled, select | Custom option row. |
[option.slot] | Same as option | Per-option renderer. |
tag | option, value, remove | Selected tag content. |
clear | — | Clear-button content. |
create | search, create | Create-row content. |
group-label | option, label | Custom group label row. |
empty | — | Empty state. |
loading | — | Loading state. |
UI Options
| Key | Description |
|---|---|
root | Root wrapper. |
input | Text input / combobox trigger. |
tags | Multiple-value tag container. |
tag | Selected tag. |
tagLabel | Default tag label. |
remove | Tag remove button. |
clear | Clear-selection button. |
hiddenInput | Hidden form input. |
content | Listbox popup. |
viewport | Scrollable viewport. |
empty | Empty state. |
loading | Loading state. |
groupLabel | Label row. |
separator | Separator row. |
option | Option row. |
indicator | Selected indicator. |
optionText | Option text wrapper. |
optionLabel | Option label. |
optionDescription | Option description. |
create | Creatable option row. |
Styling Hooks
| UI key | CSS class | Data attrs |
|---|---|---|
root | akaza-combobox | data-akaza-state, data-akaza-disabled, data-akaza-invalid, data-akaza-filled, data-akaza-focused |
input | akaza-combobox-input | Same root attrs plus ARIA combobox attrs |
tags | akaza-combobox-tags | — |
tag | akaza-combobox-tag | — |
tagLabel | akaza-combobox-tag-label | — |
remove | akaza-combobox-remove | — |
clear | akaza-combobox-clear | — |
hiddenInput | akaza-combobox-hidden-input | — |
content | akaza-combobox-content | data-akaza-state, data-akaza-side, data-akaza-align, --akaza-combobox-anchor-width, --akaza-combobox-anchor-height, --akaza-combobox-available-width, --akaza-combobox-available-height, --akaza-combobox-transform-origin, --akaza-combobox-duration |
viewport | akaza-combobox-viewport | — |
empty | akaza-combobox-empty | — |
loading | akaza-combobox-loading | — |
groupLabel | akaza-combobox-group-label | — |
separator | akaza-combobox-separator | — |
option | akaza-combobox-option | data-akaza-state, data-akaza-highlighted, data-akaza-disabled, aria-disabled |
indicator | akaza-combobox-indicator | — |
optionText | akaza-combobox-option-text | — |
optionLabel | akaza-combobox-option-label | — |
optionDescription | akaza-combobox-option-description | — |
create | akaza-combobox-create | — |
Popup entry and exit use a subtle side-aware structural transition. Override --akaza-combobox-duration to change its 120ms duration. Reduced-motion preference shortens it automatically.
Keyboard
| Key | Behavior |
|---|---|
ArrowDown / ArrowUp | Open popup and move highlight. |
Enter | Select highlighted option or request creation for unmatched text. |
Home / End | Move to first/last enabled visible option. |
Escape | Close popup. |