Skip to documentation
BoobstrapDocs
Forms

Searchable select

Implement the searchable combobox with complete Boobstrap JS, Alpine.js, and React examples.

Forms guideCopy-ready referencev0.7.0 current
Forms

Searchable select

The combobox filters human-readable labels while synchronizing the selected machine value into a hidden form input.

Boobstrap JavaScript

Type to filter, then use Arrow keys and Enter to select.
HTML · Complete Boobstrap JS markup
<form>
  <div class="bs-form-group">
    <label class="bs-label" for="team-role">Team role</label>
    <div class="bs-combobox" data-bs-combobox>
      <input
        class="bs-combobox-input"
        id="team-role"
        data-bs-combobox-input
        placeholder="Search roles"
      />
      <button
        class="bs-combobox-toggle"
        type="button"
        data-bs-combobox-toggle
        aria-label="Toggle roles"
      ></button>
      <input type="hidden" name="team_role" data-bs-combobox-value />
      <div class="bs-combobox-listbox" data-bs-combobox-listbox hidden>
        <div class="bs-combobox-option" data-bs-combobox-option data-bs-value="designer">
          Designer
        </div>
        <div class="bs-combobox-option" data-bs-combobox-option data-bs-value="engineer">
          Engineer
        </div>
        <div class="bs-combobox-option" data-bs-combobox-option data-bs-value="product-manager">
          Product manager
        </div>
        <div class="bs-combobox-option" data-bs-combobox-option data-bs-value="founder">
          Founder
        </div>
        <div class="bs-combobox-empty" data-bs-combobox-empty hidden>
          No roles found
        </div>
      </div>
    </div>
  </div>
</form>
JavaScript · Initialize only comboboxes
import "@boobstrap/boobstrap";
import { initComboboxes } from "@boobstrap/boobstrap/js/combobox";

const comboboxes = initComboboxes(document);

// Call this from your router or view cleanup hook.
export function destroyComboboxes() {
  comboboxes.forEach((combobox) => combobox.destroy());
}

Alpine.js

JavaScript · Alpine setup
import "@boobstrap/boobstrap";
import Alpine from "alpinejs";
import boobstrap from "@boobstrap/alpine";

Alpine.plugin(boobstrap);
Alpine.start();
HTML · Complete Alpine combobox
<form>
  <div class="bs-form-group">
    <label class="bs-label" for="alpine-role">Team role</label>
    <div class="bs-combobox" x-data="bsCombobox" x-bind="root">
      <input
        class="bs-combobox-input"
        id="alpine-role"
        x-bind="input"
        data-bs-combobox-input
        placeholder="Search roles"
      />
      <button
        class="bs-combobox-toggle"
        x-bind="toggleButton"
        data-bs-combobox-toggle
        aria-label="Toggle roles"
      ></button>
      <input type="hidden" name="team_role" data-bs-combobox-value />
      <div
        class="bs-combobox-listbox"
        x-bind="listbox"
        data-bs-combobox-listbox
        hidden
      >
        <div
          class="bs-combobox-option"
          x-bind="option"
          data-bs-combobox-option
          data-bs-value="designer"
        >Designer</div>
        <div
          class="bs-combobox-option"
          x-bind="option"
          data-bs-combobox-option
          data-bs-value="engineer"
        >Engineer</div>
        <div
          class="bs-combobox-option"
          x-bind="option"
          data-bs-combobox-option
          data-bs-value="product-manager"
        >Product manager</div>
        <div class="bs-combobox-empty" data-bs-combobox-empty hidden>
          No roles found
        </div>
      </div>
    </div>
  </div>
</form>

React

JSX · Complete React component
import "@boobstrap/boobstrap";
import { useCombobox } from "@boobstrap/react";

const roles = [
  { value: "designer", label: "Designer" },
  { value: "engineer", label: "Engineer" },
  { value: "product-manager", label: "Product manager" },
  { value: "founder", label: "Founder" },
];

export function TeamRoleSelect() {
  const role = useCombobox({ options: roles });

  return (
    <div className="bs-form-group">
      <label className="bs-label" htmlFor="react-role">Team role</label>
      <div className="bs-combobox" {...role.getRootProps()}>
        <input
          className="bs-combobox-input"
          id="react-role"
          placeholder="Search roles"
          {...role.getInputProps()}
        />
        <button
          className="bs-combobox-toggle"
          {...role.getToggleProps({ "aria-label": "Toggle roles" })}
        />
        <input type="hidden" name="team_role" value={role.value} readOnly />
        <div className="bs-combobox-listbox" {...role.getListboxProps()}>
          {role.filteredOptions.map((option, index) => (
            <div
              className="bs-combobox-option"
              key={option.value}
              {...role.getOptionProps(option, index)}
            >
              {option.label}
            </div>
          ))}
          {role.filteredOptions.length === 0 && (
            <div className="bs-combobox-empty">No roles found</div>
          )}
        </div>
      </div>
    </div>
  );
}

Vue

Vue · Complete searchable select
<script setup>
import "@boobstrap/boobstrap";
import { useCombobox } from "@boobstrap/vue";

const roles = [
  { value: "designer", label: "Designer" },
  { value: "engineer", label: "Engineer" },
  { value: "product-manager", label: "Product manager" },
  { value: "founder", label: "Founder" },
];
const role = useCombobox({ options: roles });
</script>

<template>
  <div class="bs-form-group">
    <label class="bs-label" for="vue-role">Team role</label>
    <div class="bs-combobox" v-bind="role.getRootProps()">
      <input class="bs-combobox-input" id="vue-role" placeholder="Search roles"
        v-bind="role.getInputProps()" />
      <button class="bs-combobox-toggle"
        v-bind="role.getToggleProps({ 'aria-label': 'Toggle roles' })"></button>
      <input type="hidden" name="team_role" :value="role.value" />
      <div class="bs-combobox-listbox" v-bind="role.getListboxProps()">
        <div v-for="(option, index) in role.filteredOptions" :key="option.value"
          class="bs-combobox-option"
          v-bind="role.getOptionProps(option, index)">
          {{ option.label }}
        </div>
        <div v-if="role.filteredOptions.length === 0" class="bs-combobox-empty">
          No roles found
        </div>
      </div>
    </div>
  </div>
</template>
Choose one owner: initialize the plain JavaScript controller, Alpine adapter, React hook, or Vue composable—not more than one on the same combobox. See the React and Vue adapter guides for controlled state and SSR rules.