Skip to content

Forms

Combobox

An editable input paired with a filterable listbox.

stableEnhancer: enhanceComboboxBuilt on <input> + <ul role="listbox">hydrateless/combobox.css

An editable input paired with a filterable listbox, following the WAI-ARIA combobox pattern. Before JavaScript runs, the stylesheet reveals the listbox on :focus-within so the options are reachable. The enhancer marks the root data-hl-ready, then adds type-to-filter, keyboard navigation that skips disabled options, aria-activedescendant wiring, and selection.

Combobox

Type to filter, use Up/Down to move (Alt+Down expands without moving), PageUp/PageDown to jump, and Enter to select. Home/End stay with the text caret. Disabled options are skipped.

Live
  • Apple
  • Banana
  • Cherry (out of season)
  • Grape

JavaScript

This component ships an optional enhancer. With auto-init it loads automatically; to wire it yourself, import it directly:

import { enhanceCombobox } from '@hydrateless/enhancers/combobox';

const handle = enhanceCombobox(document);
// handle.api  -> imperative controls
// handle.destroy()  -> tear everything down

Props

The framework bindings expose these props (and forward the rest to the root element).

PropTypeDefaultDescription
valuestringNot setControlled committed value; pair with `onValueChange` (Vue: `v-model`, Svelte: `bind:value`).
defaultValuestringNot setUncontrolled initial value; pre-fills the input.
onValueChange(value: string) => voidNot setCalled when a selection is committed.
openbooleanNot setControlled listbox visibility; pair with `onOpenChange` (Vue: `v-model:open`, Svelte: `bind:open`).
defaultOpenbooleanfalseExpand the listbox on mount.
onOpenChange(open: boolean) => voidNot setCalled after the listbox expands or collapses.
filterbooleantrueHide options that do not match the typed query.
autoHighlightbooleantrueHighlight the first match automatically while typing.
ComboboxOption.disabledbooleanfalseRenders `aria-disabled="true"`; the option is skipped and cannot be selected.

Events and callbacks

Event / CallbackPayloadDescription
hl:select{ value: string, option: HTMLElement }Cancelable CustomEvent on selection; call `preventDefault()` to keep the input unchanged.
hl:change{ value: string }Fires after the value commits (also the `onValueChange` callback).
hl:open-change{ open: boolean }Fires when the listbox expands or collapses (also the `onOpenChange` callback).

CSS variables

Override these on any ancestor to theme the component. See the theme studio to preview changes live.

CSS variableUsed for
--hl-overlayListbox background.
--hl-borderListbox and input border.
--hl-primary-subtleActive option highlight.
--hl-focus-shadowFocus ring on the input.

Accessibility

  • The input becomes role="combobox" with aria-expanded, aria-controls, aria-haspopup="listbox", and aria-activedescendant.
  • The active option is tracked with aria-selected; Esc, Tab, or an outside click closes the list.
  • Options with aria-disabled="true" are skipped during navigation and cannot be committed.

Released under the MIT License.