createCombobox
Low-level combobox coordinator for custom implementations. Most users should use the Combobox component instead.
Usage
import { createCombobox } from '@vuetify/v0'
const combobox = createCombobox({ strict: true })
// Register items with the underlying selection
combobox.selection.register({ id: 'apple', value: 'Apple' })
combobox.selection.register({ id: 'banana', value: 'Banana' })
combobox.selection.register({ id: 'cherry', value: 'Cherry' })
// Open the dropdown
combobox.open()
// Select an item — in single mode this updates the query and closes
combobox.select('banana')
// combobox.query.value === 'Banana'
// combobox.isOpen.value === false
// Filter is pristine after selection — all items still visible
// combobox.pristine.value === true
// Once user types, the filter activates
combobox.query.value = 'ch'
// combobox.pristine.value === false
// combobox.filtered.value === Set { 'cherry' }Architecture
createCombobox orchestrates four independent primitives without extending their chains — it composes them. The adapter translates queries into a filtered set; virtual focus uses that set to skip hidden items.
Reactivity
| Property | Type | Reactive | Notes |
|---|---|---|---|
query | ShallowRef<string> | Current input text | |
pristine | ShallowRef<boolean> | true after selection; false once user types | |
filtered | Ref<Set<ID>> | IDs that pass the current filter | |
isEmpty | Ref<boolean> | true when filtered set is empty | |
isLoading | ShallowRef<boolean> | Forwarded from adapter | |
isOpen | ShallowRef<boolean> | Popover open state | |
selection | SelectionContext | — | Full selection API |
popover | PopoverReturn | — | Popover positioning API |
cursor | VirtualFocusReturn | — | Keyboard focus API |
inputEl | ShallowRef<HTMLElement | null> | Reference to the <input> element |
Options
interface ComboboxOptions {
multiple?: MaybeRefOrGetter<boolean> // Enable multi-select
mandatory?: MaybeRefOrGetter<boolean> // Prevent deselecting last item
disabled?: MaybeRefOrGetter<boolean> // Disable all interaction
strict?: MaybeRefOrGetter<boolean> // Revert query on close if no match
adapter?: ComboboxAdapter // Filtering strategy (default: ClientComboboxAdapter)
displayValue?: (value: unknown) => string // Format selected value for display in input
id?: string // Base ID for ARIA attributes
name?: string // Hidden input name for form submission
form?: string // Associated form ID
}Context Object
createCombobox returns a ComboboxContext with the following API surface:
| Member | Type | Description |
|---|---|---|
open() | () => void | Opens the dropdown |
close() | () => void | Closes; applies strict revert if needed |
toggle() | () => void | Opens or closes |
select(id) | (id: ID) => void | Selects an item by ID |
clear() | () => void | Resets query and deselects all |
id | string | Base ID used for ARIA relationships |
inputId | string | ${id}-input |
listboxId | string | ${id}-listbox |
multiple | boolean | Resolved multiple flag |
strict | MaybeRefOrGetter<boolean> | Strict option ref |
disabled | MaybeRefOrGetter<boolean> | Disabled option ref |
name | string | undefined | Form field name |
form | string | undefined | Associated form ID |
Adapters
Adapters extend ComboboxAdapter and translate a reactive query into a filtered ID set.
abstract class ComboboxAdapter {
abstract setup (context: ComboboxAdapterContext): ComboboxAdapterResult
}
interface ComboboxAdapterResult {
filtered: Ref<Set<ID>> // IDs that should be visible
isLoading: ShallowRef<boolean> // shows loading state in the UI
isEmpty: Ref<boolean> // true when no items match the query
}The context exposes query (the current search string), selection (the underlying selection context), and items (all registered IDs). Return the three refs above and the combobox wires them to the dropdown state automatically.
ClientComboboxAdapter
The default. Filters registered items locally using substring matching (case-insensitive). Pass custom filter options to override the matching logic:
import { ClientComboboxAdapter, createCombobox } from '@vuetify/v0'
const combobox = createCombobox({
adapter: new ClientComboboxAdapter({
filter: (query, value) => String(value).toLowerCase().startsWith(query.toLowerCase()),
}),
})ServerComboboxAdapter
A pass-through adapter that shows all registered items and sets isLoading to false. Use this when filtering is performed server-side — watch combobox.query to drive your own fetch:
import { ServerComboboxAdapter, createCombobox, useCombobox } from '@vuetify/v0'
import { watch } from 'vue'
const combobox = createCombobox({ adapter: new ServerComboboxAdapter() })
// In a component that injects the context:
const { query } = useCombobox()
watch(query, async q => {
const results = await fetch(`/api/search?q=${q}`).then(r => r.json())
// Update items via combobox.selection.register / unregister
})See the Combobox server example for a complete integration.
Strict Mode
When strict: true, closing the dropdown without an active selection reverts the query:
If an item is selected,
queryresets to that item’s label.If nothing is selected,
queryresets to''.
Non-strict mode (default) leaves whatever text the user typed in place.
aria-autocomplete="both" is set automatically on the input when strict is enabled, per the WAI-ARIA combobox pattern.
Pristine Flag
pristine tracks whether the query reflects the current selection or is a live filter:
Starts as
true(no user input yet).Becomes
falsewhen the user types — the adapter receives the raw query.Resets to
trueafter a selection (select(id)), so reopening the dropdown always shows all items instead of the previous typed query.
// The adapter receives `search`, not `query` directly
const search = toRef(() => pristine.value ? '' : query.value)
const { filtered } = adapter.setup({ query: search, items })Multi-Select Behavior
In multiple mode, select(id) differs from single mode:
Toggles the item (select → deselect on second click) via
selection.toggle().Clears the query so the user can search for the next item.
Keeps the dropdown open.
Highlights the clicked item via
cursor.highlight(id)so ArrowDown continues from that position.Refocuses the input so keyboard navigation continues immediately.
Dependency Injection
Use createComboboxContext to get a DI-aware trinity for component-based setups:
import { createComboboxContext, useCombobox } from '@vuetify/v0'
// In a Root component
const [useMyCombobox, provideMyCombobox, context] = createComboboxContext({
namespace: 'my-combobox',
strict: true,
})
provideMyCombobox(context)
// In any child component
const combobox = useCombobox('my-combobox')useCombobox(namespace?) injects the nearest combobox context (default namespace: 'v0:combobox').