Vize

Combobox

Accessible, unstyled Combobox: an editable APG combobox with a typed listbox popup. Popup structure is shared with Select: ComboboxContent, ComboboxItem, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxViewport, ComboboxItemIndicator, ComboboxScrollButton, and ComboboxVirtualizer are the Select parts, which publish data-vize-ui="combobox-*" inside a ComboboxRoot.

Package @vizejs/ui/combobox
Maturity stable
Own the source vize lib pull combobox
Requires collection, composite-navigation, context, controllable-state, dismissable-layer, id, portal, positioner, presence, select, typeahead, virtualizer
Aliases combobox, autocomplete, typeahead select, searchable select, multi select chips
Covers WAI-ARIA combobox pattern (listbox popup), Radix/Reka UI Combobox, React Aria ComboBox, Headless UI Combobox, Ark UI Combobox

Usage

import { Combobox, ComboboxRoot, ComboboxAnchor, ComboboxChip, ComboboxChipRemove, ComboboxCreateItem, ComboboxEmpty, ComboboxInput, ComboboxLoading, ComboboxTrigger, ComboboxContent, ComboboxGroup, ComboboxItem, ComboboxItemIndicator, ComboboxLabel, ComboboxScrollButton, ComboboxSeparator, ComboboxViewport, ComboboxVirtualizer } from "@vizejs/ui/combobox";

Or copy the source into your project with vize lib pull combobox (see Source Distribution).

API

Combobox<T, Multiple extends boolean = false>

Source: src/families/selection/combobox/combobox-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
modelValue SelectModelValue<T, Multiple> undefined Controlled selection: T | null, or readonly T[] when multiple is true.
defaultValue SelectModelValue<T, Multiple> undefined Initial selection for uncontrolled use and the value restored by reset.
multiple Multiple false Allow selecting several options, rendered as chips. The literal type decides the model type.
items readonly T[] undefined Every option value. Enables typed inference, root-side filtering exposed as filteredItems, closed-state labels, and virtualization.
loadItems ComboboxLoader<T> undefined Async item source called (debounced) with the typed query. Its results replace items.
debounce number 200 Debounce in milliseconds before loadItems runs for a new query.
by SelectBy<T> undefined Compare values by a property key or with a custom equality function.
itemText (value: T) => string undefined Human-readable text for a value: the input label after selection, chip text, and filter text.
itemDisabled (value: T) => boolean undefined Disable individual values.
formValue (value: T) => string undefined Serialize a value for native form submission.
filter ComboboxFilter<T> | false undefined Filter deciding option visibility; false disables filtering (server-side or custom lists). Defaults to an accent- and case-insensitive "contains" match.
autocomplete ComboboxAutocomplete "list" APG autocomplete behavior, mirrored to aria-autocomplete.
strict boolean true Restrict the value to listed options. When false, free text is kept and submitted.
createOption (text: string) => T undefined Build a value from free text, enabling the create option and Enter-to-create.
inputValue string undefined Controlled input text. undefined selects uncontrolled behavior.
defaultInputValue string "" Initial input text for uncontrolled use.
open boolean undefined Controlled open state. undefined selects uncontrolled behavior.
defaultOpen boolean false Initial open state for uncontrolled use.
openOnFocus boolean false Open the popup when the input gains focus.
autoHighlight boolean true Highlight the first visible option while typing.
closeOnSelect boolean undefined Close after an option is chosen. undefined closes in single mode only.
clearOnEscape boolean true Let Escape clear the text (and single selection) while the popup is closed.
loop boolean false Wrap arrow-key navigation at the first and last option.
disabled boolean false Disable the input, options, and form submission.
readonly boolean false Keep the value visible and submittable but prevent editing.
required boolean false Require a selection (or free text when not strict) for native validation.
name string undefined Form control name used by the hidden inputs.
form string undefined Id of the form owner when the combobox renders outside its <form>.
dir "ltr" | "rtl" "ltr" Reading direction published to parts.
ariaInvalid ComboboxAriaInvalid false Invalid state announced to assistive technology.

Events

Event Payload Description
update:modelValue [value: SelectModelValue<T, Multiple>] Fired when the selection requests a new controlled value (T | null or readonly T[]).
change [ value: SelectModelValue<T, Multiple>, previous: SelectModelValue<T, Multiple>, nativeEvent: Event, ] Fired after a user interaction changes the selection: next value, previous value, and the native event.
update:inputValue [text: string] Fired when the input text requests a new controlled value.
update:open [open: boolean] Fired when the popup requests a controlled open value.
open-change [open: boolean, previous: boolean, nativeEvent: Event | null] Fired after any distinct open-state request with the next state, previous state, and triggering event.
create [value: T, text: string] Fired when createOption builds a new value from the typed text, before it is selected.

Slots

Slot Slot props Description
default ComboboxSlotState<T> Compound Combobox parts. Receives selection, text, filtered items, and loader state.

Exposed

Member Type Description
clear —
deselect —
focus —
inputValue —
open —
reload —
reset —
select —
selected —
setInputValue —
setOpen —

ComboboxRoot<T, Multiple extends boolean = false>

Source: src/families/selection/combobox/combobox-root.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned base id. null and undefined select a deterministic fallback.
modelValue SelectModelValue<T, Multiple> undefined Controlled selection: T | null, or readonly T[] when multiple is true.
defaultValue SelectModelValue<T, Multiple> undefined Initial selection for uncontrolled use and the value restored by reset.
multiple Multiple false Allow selecting several options, rendered as chips. The literal type decides the model type.
items readonly T[] undefined Every option value. Enables typed inference, root-side filtering exposed as filteredItems, closed-state labels, and virtualization.
loadItems ComboboxLoader<T> undefined Async item source called (debounced) with the typed query. Its results replace items.
debounce number 200 Debounce in milliseconds before loadItems runs for a new query.
by SelectBy<T> undefined Compare values by a property key or with a custom equality function.
itemText (value: T) => string undefined Human-readable text for a value: the input label after selection, chip text, and filter text.
itemDisabled (value: T) => boolean undefined Disable individual values.
formValue (value: T) => string undefined Serialize a value for native form submission.
filter ComboboxFilter<T> | false undefined Filter deciding option visibility; false disables filtering (server-side or custom lists). Defaults to an accent- and case-insensitive "contains" match.
autocomplete ComboboxAutocomplete "list" APG autocomplete behavior, mirrored to aria-autocomplete.
strict boolean true Restrict the value to listed options. When false, free text is kept and submitted.
createOption (text: string) => T undefined Build a value from free text, enabling the create option and Enter-to-create.
inputValue string undefined Controlled input text. undefined selects uncontrolled behavior.
defaultInputValue string "" Initial input text for uncontrolled use.
open boolean undefined Controlled open state. undefined selects uncontrolled behavior.
defaultOpen boolean false Initial open state for uncontrolled use.
openOnFocus boolean false Open the popup when the input gains focus.
autoHighlight boolean true Highlight the first visible option while typing.
closeOnSelect boolean undefined Close after an option is chosen. undefined closes in single mode only.
clearOnEscape boolean true Let Escape clear the text (and single selection) while the popup is closed.
loop boolean false Wrap arrow-key navigation at the first and last option.
disabled boolean false Disable the input, options, and form submission.
readonly boolean false Keep the value visible and submittable but prevent editing.
required boolean false Require a selection (or free text when not strict) for native validation.
name string undefined Form control name used by the hidden inputs.
form string undefined Id of the form owner when the combobox renders outside its <form>.
dir "ltr" | "rtl" "ltr" Reading direction published to parts.
ariaInvalid ComboboxAriaInvalid false Invalid state announced to assistive technology.

Events

Event Payload Description
update:modelValue [value: SelectModelValue<T, Multiple>] Fired when the selection requests a new controlled value (T | null or readonly T[]).
change [ value: SelectModelValue<T, Multiple>, previous: SelectModelValue<T, Multiple>, nativeEvent: Event, ] Fired after a user interaction changes the selection: next value, previous value, and the native event.
update:inputValue [text: string] Fired when the input text requests a new controlled value.
update:open [open: boolean] Fired when the popup requests a controlled open value.
open-change [open: boolean, previous: boolean, nativeEvent: Event | null] Fired after any distinct open-state request with the next state, previous state, and triggering event.
create [value: T, text: string] Fired when createOption builds a new value from the typed text, before it is selected.

Slots

Slot Slot props Description
default ComboboxSlotState<T> Compound Combobox parts. Receives selection, text, filtered items, and loader state.

Exposed

Member Type Description
selected readonly T[] Selected values.
inputValue string Current input text.
open boolean Whether the popup is open.
setOpen (open: boolean, event?: Event | null) => boolean Request a specific open state.
setInputValue (text: string) => void Replace the input text as if typed (filters and loads).
select (value: T) => boolean Select a value (toggle in multiple mode).
deselect (value: T) => boolean Deselect a value.
clear () => boolean Clear the selection and the text.
reset () => void Restore defaults for selection and text.
reload () => void Re-run the async loader for the current query.
focus (options?: FocusOptions) => void Focus the input.

ComboboxAnchor

Source: src/families/selection/combobox/combobox-anchor.vue

Slots

Slot Slot props Description
default — Chips, the input, and the toggle button. The popup is positioned against this box.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

ComboboxChip<T>

Source: src/families/selection/combobox/combobox-chip.vue

Props

Prop Type Default Description
value (required) T required Selected value rendered by this chip.

Slots

Slot Slot props Description
default ComboboxChipSlotState<T> Chip content, usually the text plus a ComboboxChipRemove.

ComboboxChipRemove

Source: src/families/selection/combobox/combobox-chip-remove.vue

Props

Prop Type Default Description
ariaLabel string undefined Accessible name. Defaults to Remove <chip text>.

Slots

Slot Slot props Description
default — Decorative remove icon.

ComboboxCreateItem

Source: src/families/selection/combobox/combobox-create-item.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned option id. null and undefined select a deterministic fallback.

Slots

Slot Slot props Description
default { readonly query: string; readonly active: boolean } Create-option label, e.g. Create "{{ query }}". Receives the typed text and highlight state.

ComboboxEmpty

Source: src/families/selection/combobox/combobox-empty.vue

Slots

Slot Slot props Description
default { readonly query: string } Message shown when no option is visible and nothing is loading. Receives the query.

ComboboxInput

Source: src/families/selection/combobox/combobox-input.vue

Props

Prop Type Default Description
placeholder string undefined Hint text shown while the input is empty.
ariaLabel string undefined Accessible name when no visible label supplies one.
ariaLabelledby string undefined Space-separated ids of visible labels; also labels the listbox.
ariaDescribedby string undefined Space-separated ids that describe the combobox.
ariaErrormessage string undefined Id of the validation message announced while invalid.
autocomplete string "off" Native browser autofill hint; off keeps browser suggestions out of the listbox's way.
spellcheck boolean false Native spellchecking.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.
focus —

ComboboxLoading

Source: src/families/selection/combobox/combobox-loading.vue

Slots

Slot Slot props Description
default { readonly query: string } Content shown while loadItems is pending. Receives the query being loaded.

ComboboxTrigger

Source: src/families/selection/combobox/combobox-trigger.vue

Props

Prop Type Default Description
ariaLabel string "Show suggestions" Accessible name of the toggle button.

Slots

Slot Slot props Description
default { readonly open: boolean } Decorative toggle content such as a chevron. Receives the open state.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

ComboboxContent

Source: src/families/selection/select/select-content.vue

Props

Prop Type Default Description
position SelectPosition "popper" popper anchors below the trigger; item-aligned overlays the selected option on the trigger.
placement Placement "bottom-start" Preferred popper placement before collision handling.
strategy PositionerStrategy "fixed" CSS positioning mode published on the floating host.
offset number 4 Gap between trigger and listbox in popper mode.
collisionPadding number 8 Viewport padding the listbox should not cross.
flip boolean true Flip to the opposite side when the preferred side overflows more (popper mode).
shift boolean true Shift the listbox back into the viewport.
size boolean true Publish available-size CSS variables and constrain the host.
hide boolean true Hide when the trigger scrolls out of view.
forceMount boolean false Keep options mounted (hidden) while closed so labels and typeahead work before first open.
to string | HTMLElement "body" CSS selector or element the popup is moved into.
portalDisabled boolean false Render in place instead of teleporting.
defer boolean true Keep content in place until the portal target exists, avoiding SSR mismatch.
closeOnEscape boolean true Let Escape close the popup.
closeOnPointerDownOutside boolean true Let an outside pointer-down close the popup.
ariaLabel string undefined Accessible name for the listbox when the trigger label is not enough.
ariaLabelledby string undefined Space-separated ids labelling the listbox. Defaults to the trigger.

Events

Event Payload Description
escape-key-down [event: SelectEscapeKeyDownEvent] Fired before Escape closes the popup. Call preventDefault() to keep it open.
pointer-down-outside [event: SelectPointerDownOutsideEvent] Fired before an outside pointer-down closes the popup. Call preventDefault() to keep it open.
dismiss [event: SelectDismissEvent] Fired after an unprevented dismissal request closes the popup.

Slots

Slot Slot props Description
default SelectContentSlotState Options, groups, separators, viewport, and scroll buttons. Receives open state and placement.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

ComboboxGroup

Source: src/families/selection/select/select-group.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned group id. null and undefined select a deterministic fallback.
ariaLabel string undefined Accessible group name used instead of a SelectLabel.

Slots

Slot Slot props Description
default — A SelectLabel followed by the group's options.

ComboboxItem<T>

Source: src/families/selection/select/select-item.vue

Props

Prop Type Default Description
id string | null undefined Consumer-owned option id. null and undefined select a deterministic fallback.
value (required) T required Option value compared with the root selection through by.
disabled boolean false Disable this option.
textValue string undefined Explicit label for typeahead and SelectValue. undefined extracts the option text.
index number undefined Absolute index inside the root items, required inside SelectVirtualizer.
ariaLabel string undefined Accessible name when the option text is not enough.

Slots

Slot Slot props Description
default SelectItemSlotState<T> Option content. Receives selected, active, and disabled state.

Exposed

Member Type Description
active —
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.
select —
selected —
value —

ComboboxItemIndicator

Source: src/families/selection/select/select-item-indicator.vue

Props

Prop Type Default Description
forceMount boolean false Render while the option is unselected too, publishing data-state for CSS transitions.

Slots

Slot Slot props Description
default { readonly selected: boolean } Indicator content such as a check mark. Receives the option selection state.

ComboboxLabel

Source: src/families/selection/select/select-label.vue

Slots

Slot Slot props Description
default — Visible group heading text.

ComboboxScrollButton

Source: src/families/selection/select/select-scroll-button.vue

Props

Prop Type Default Description
direction (required) SelectScrollDirection required Scroll direction driven while hovered or pressed.
step number 32 Pixels scrolled per tick.
interval number 50 Milliseconds between ticks while hovered or pressed.

Slots

Slot Slot props Description
default { readonly direction: SelectScrollDirection } Decorative arrow content. Receives the scroll direction.

Exposed

Member Type Description
scrollOnce —
update —
visible —

ComboboxSeparator

Source: src/families/selection/select/select-separator.vue

Slots

Slot Slot props Description
default — Optional decorative separator content.

ComboboxViewport

Source: src/families/selection/select/select-viewport.vue

Slots

Slot Slot props Description
default — Scrollable options region. Scroll buttons and SelectVirtualizer observe this element.

Exposed

Member Type Description
element Readonly<ShallowRef<HTMLElement | null>> Template ref to the rendered root element.

ComboboxVirtualizer<T>

Source: src/families/selection/select/select-virtualizer.vue

Props

Prop Type Default Description
items (required) readonly T[] required Every option value in display order; only the visible window is rendered.
estimateItemSize number 32 Estimated option height in CSS pixels used until options are measured.
overscan number 4 Options rendered beyond each edge of the visible window.
initialViewportHeight number 256 Viewport height assumed for server rendering and before measurement.
getItemKey (item: T, index: number) => string | number undefined Stable render key for an option. Defaults to its index.

Slots

Slot Slot props Description
default SelectVirtualItemSlotState<T> Render one SelectItem with :value="item" and :index="index".

Exposed

Member Type Description
scrollToIndex —
totalSize —
virtualItems —

Behavior

Contract

Combobox is a headless, strongly typed editable combobox following the WAI-ARIA APG combobox with listbox popup pattern. combobox-root.vue is generic over the option value type T and a Multiple literal: the model is T | null, or readonly T[] (rendered as chips) when multiple is true. T is inferred from items, loadItems, modelValue, defaultValue, or createOption.

combobox-input.vue renders a native <input role="combobox"> that keeps DOM focus and exposes the highlighted option through aria-activedescendant and aria-autocomplete. The popup reuses Select's structural parts — content, item, group, label, separator, viewport, scroll button, item indicator, and virtualizer — which publish data-vize-ui="combobox-*" inside a Combobox and share the collection registry, composite navigation, positioner, dismissable layer, and virtualizer. combobox-anchor.vue is the positioning box that keeps presses inside the input, combobox-trigger.vue a non-tabbable toggle button, combobox-chip.vue and combobox-chip-remove.vue render multiple selections, combobox-create-item.vue offers to create a value from free text, and combobox-empty.vue/combobox-loading.vue render status content.

Filtering is injectable (filter), accent- and case-insensitive by default, and disabled with filter: false. loadItems(query, { signal }) is an async item hook with debouncing and abort-on-supersede. Named comboboxes submit through hidden inputs; the visible input never submits.

Public Surface

Surface Contract
ComboboxRoot props id, modelValue, defaultValue, multiple, items, loadItems, debounce, by, itemText, itemDisabled, formValue, filter, autocomplete, strict, createOption, inputValue, defaultInputValue, open, defaultOpen, openOnFocus, autoHighlight, closeOnSelect, clearOnEscape, loop, disabled, readonly, required, name, form, dir, ariaInvalid
ComboboxRoot emits update:modelValue(value), change(value, previous, nativeEvent), update:inputValue(text), update:open(open), open-change(open, previous, nativeEvent), create(value, text)
ComboboxRoot slot state selected, selectedText, inputValue, query, filteredItems, open, empty, loading, status, error, disabled, selectionMode, state, remove
ComboboxRoot expose selected, inputValue, open, setOpen, setInputValue, select, deselect, clear, reset, reload, focus
ComboboxInput props placeholder, ariaLabel, ariaLabelledby, ariaDescribedby, ariaErrormessage, autocomplete, spellcheck
ComboboxChip value; slot default({ value, text, disabled, remove })
Parts root, anchor, input, trigger, chip, chip-remove, create-item, empty, loading, native, plus the shared popup parts
Root data attributes data-vize-ui="combobox", data-state, data-selection-mode, data-autocomplete, data-disabled, data-readonly, data-required, data-invalid, data-empty, data-loading

Normative Behavior

# State Input Outcome Proven by
C1 closed render text input with role="combobox", aria-autocomplete, aria-expanded="false", no aria-controls, autocomplete="off"; no popup renders APG combobox semantics on a native text input
C2 list type opens, filters accent- and case-insensitively, highlights the first visible option; Enter selects, fills the label, closes; change carries the key event typing opens, filters accent-insensitively, highlights the first match, and Enter selects
C3 items mode type root exposes filteredItems; injected filters replace the default; filter: false keeps every option; empty content shows when nothing matches items mode exposes filteredItems and filter functions are injectable
C4 inline type / delete completes the first matching option after the typed prefix, selects the completion, highlights it, does not filter; deletions never re-complete inline autocomplete completes the first match and selects the completion
C5 both type filters and completes inline both autocomplete filters and completes
C6 none type lists every option and highlights nothing autocomplete none lists everything without highlighting
C7 strict / free text blur strict restores the selected label; strict: false keeps and submits the typed text without changing the selection strict mode restores the selected label on blur; free text survives otherwise
C8 strict single clear the text clears the selection clearing the text clears a strict single selection
C9 createOption type a new value / Enter shows the create option (hidden on exact matches), highlights it first, emits create(value, text) then selects the created value createOption offers a create option unless the text matches exactly
C10 create option visible click creates the typed value clicking the create option creates the typed value
C11 multiple choose / Backspace on empty / chip remove renders chips, clears the text, keeps the popup open; Backspace at caret 0 removes the last chip; the non-tabbable remove button removes its chip multiple mode renders chips, keeps the popup open, and deletes with Backspace
K1 closed / open ArrowDown / ArrowUp / Alt+ArrowDown / Alt+ArrowUp / PageDown / Escape / Tab / Home ArrowDown opens on the selection, ArrowUp on the last option, Alt+ArrowDown opens without highlight, Alt+ArrowUp and Escape close, Tab closes without preventing focus, Home/End keep caret movement, Escape while closed clears text and single selection keyboard matrix: arrows, Alt+arrows, PageDown, Escape, and Tab
K2 nothing highlighted Enter not prevented, so native form submission proceeds Enter without a highlighted option keeps native form submission
P1 any toggle button / option pointer-down / anchor press toggle opens without taking focus (tabindex=-1); option and anchor presses keep focus in the input the toggle button and anchor keep focus in the input
P2 openOnFocus focus opens openOnFocus opens when the input gains focus
P3 disabled / readonly keys / Backspace disabled inputs never open; readonly inputs keep the value and chips disabled and readonly inputs refuse edits
P4 controlled inputValue type emits update:inputValue and renders the parent text controlled inputValue waits for the parent
P5 no provider mount a part throws VIZE_UI_CONTEXT_MISSING parts require a Combobox provider
P6 shared popup parts render inside a Combobox publish combobox-* part names; the listbox is labelled by the input's ariaLabelledby Select popup parts publish combobox part names inside a ComboboxRoot
A1 loadItems open / type / newer query / reject / unmount loads on open and per query, publishes loading and hides empty content meanwhile, aborts superseded requests, keeps last results on error, aborts on unmount loadItems runs on open and per query, exposes loading, and ignores stale responses
A2 loadItems, debounce rapid typing opening loads at once; later keystrokes load only the settled query loadItems is debounced
V1 virtualized type / PageDown / Enter only a window of filtered results renders; navigation reaches options outside it virtualized combobox lists navigate filtered results beyond the window
F1 named submit hidden inputs carry formValue/by serialization; the visible input has no name submits the serialized selection through hidden inputs, not the visible text
F2 named, multiple submit one hidden input per value multiple selections submit one hidden input per value
F3 required checkValidity() the input is natively required until a value is selected; failure marks aria-invalid required uses native validation on the input until something is selected
F4 form reset restores the default selection and text form reset restores the default selection and text
U1 helpers normalize / filter / complete normalizeComboboxText, containsComboboxFilter, startsWithComboboxFilter, inlineComboboxCompletion are pure filter helpers normalize accents, case, and inline completion

SSR

Ids come from the deterministic-id primitive, the popup renders in place until the portal hydrates, and the loader never runs on the server. Closed single and open multiple trees render byte-identical markup and hydrate without warnings (renders byte-identical single Combobox markup with the selected label, renders byte-identical open multiple Combobox markup with chips, hydrates closed single and open multiple Comboboxes without mismatches). Pass itemText so the input renders the selected label on the server.