Combobox
Combobox combines a text input with a role="listbox" popup. Users can filter options, navigate suggestions, and select a value. Use Select without text input.
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>
Async results and composition
Result updates preserve the active option by value. If that option disappears, Combobox clears its active target. Enter during IME composition does not select an option.
Custom option slots retain component identity during ordinary updates, preserving local state and focus.
Native Form Reset
A native form reset restores the initial model and clears interaction state. Calling preventDefault() on the reset event preserves the current value. Reset updates v-model without emitting value-change.
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 transitions follow their placement side and last 120ms. Set --akaza-combobox-duration to change the duration. Reduced-motion mode removes the visible transition.
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. |