Skip to content
HyperUX Experimental
Demo

Searchable listbox input with keyboard navigation and optional multiple selection.


Alpine.js Combobox

huxCombobox provides combobox behavior for Alpine.js with filtered option rendering, keyboard navigation, and optional multiple selection. Use it when you need behavior-only combobox logic that you can pair with your own markup and styles.

API

huxCombobox(config)

Returns an Alpine data object with:

Internal helper methods are private implementation details and are not part of the supported API contract.

Options

Quick Start

<div
  x-data="huxCombobox({
    optionItems: [
      { label: 'Apple', value: 'apple' },
      { label: 'Banana', value: 'banana' },
      { label: 'Cherry', value: 'cherry' }
    ]
  })"
  x-on:click.outside="closeList()"
>
  <label x-bind:for="comboboxInputId">Fruit</label>

  <input
    x-ref="comboboxInput"
    x-model="searchQuery"
    x-bind:id="comboboxInputId"
    x-bind:aria-expanded="isOpen.toString()"
    x-bind:aria-controls="listboxId"
    role="combobox"
    aria-autocomplete="list"
    aria-haspopup="listbox"
    x-on:input="onInputChange()"
    x-on:keydown.down.prevent="focusNextOptionItem()"
    x-on:keydown.up.prevent="focusPreviousOptionItem()"
    x-on:keydown.enter.prevent="selectFocusedOptionItem()"
    x-on:keydown.escape.stop.prevent="closeList()"
  />

  <div x-ref="comboboxListbox" x-bind:id="listboxId" role="listbox" x-cloak x-show="isOpen">
    <template x-for="({ optionItem, sourceIndex }) in filteredOptionItems" x-bind:key="sourceIndex">
      <button
        type="button"
        role="option"
        x-bind:id="optionItemId(sourceIndex)"
        x-on:click="toggleOptionItem(optionItem)"
        x-text="optionItem.label"
      ></button>
    </template>
  </div>
</div>

Common Usage Patterns

Multiple Selection

huxCombobox({
  optionItems: [
    { label: 'Apple', value: 'apple' },
    { label: 'Apricot', value: 'apricot' },
  ],
  acceptMultiple: true,
})

Keep List Closed Until Search Starts

huxCombobox({
  optionItems: [
    { label: 'Apple', value: 'apple' },
    { label: 'Banana', value: 'banana' },
  ],
  hideOptionItemsWhenSearchQueryEmpty: true,
})

Behavior Contract

Error Handling

Accessibility Notes

Notes