v1.1.1

Combobox

An input with a dropdown list for searching and selecting from a set of options.

Interactive Requires: veritheme.js JS init: automatic

Default

A searchable input with a dropdown list of options. Try searching and selecting.

html
Next.js
SvelteKit
Nuxt
Remix
Astro
No results found.
<div class="vt-w-72 vt-relative vt-combobox-wrapper">
  <div class="vt-relative">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-search vt-absolute vt-left-3 vt-top-1/2 vt--translate-y-1/2 vt-w-4 vt-h-4 vt-text-foreground-muted">
      <path d="m21 21-4.34-4.34"></path><circle cx="11" cy="11" r="8"></circle>
    </svg>
    <input type="text" placeholder="Search framework..." onfocus="openCombobox('cb-default')" oninput="filterCombobox(this, 'cb-default')" class="vt-input vt-pl-10" aria-label="Search framework...">
  </div>
  <div id="cb-default" class="vt-dropdown-menu vt-w-full vt-mt-1" data-combobox-content="">
    <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Next.js
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      SvelteKit
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Nuxt
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Remix
    </div>
    <div class="vt-combobox-item vt-selected" onclick="selectComboboxItem(this)">

      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="vt-w-4 vt-h-4 vt-shrink-0 vt-text-info-fill vt-combobox-icon"><path d="M20 6 9 17l-5-5"></path></svg>
      Astro
    </div>
    <div class="vt-combobox-empty vt-hidden vt-py-4 vt-text-center vt-text-sm vt-text-foreground-muted">No results found.</div>
  </div>
</div>

With Groups

Combobox with options organized into labeled groups. Icons are preserved on selection.

html
Suggestions
Calendar
Search
Settings
Results
Calculator
Profile
No results found.
<div class="vt-w-72 vt-relative vt-combobox-wrapper" data-keep-icons="true">
  <div class="vt-relative">
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-search vt-absolute vt-left-3 vt-top-1/2 vt--translate-y-1/2 vt-w-4 vt-h-4 vt-text-foreground-muted">
      <path d="m21 21-4.34-4.34"></path><circle cx="11" cy="11" r="8"></circle>
    </svg>
    <input type="text" placeholder="Search..." onfocus="openCombobox('cb-groups')" oninput="filterCombobox(this, 'cb-groups')" class="vt-input vt-pl-10" aria-label="Search...">
  </div>
  <div id="cb-groups" class="vt-dropdown-menu vt-w-full vt-mt-1" data-combobox-content="">
    <div class="vt-combobox-group" data-combobox-group="">
      <div class="vt-text-xs vt-font-semibold vt-text-foreground-muted vt-px-2 vt-py-1.5">Suggestions</div>
      <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-calendar vt-w-4 vt-h-4 vt-shrink-0 vt-text-foreground-muted">
          <path d="M8 2v4"></path><path d="M16 2v4"></path><rect width="18" height="18" x="3" y="4" rx="2"></rect><path d="M3 10h18"></path>
        </svg>
        Calendar
      </div>
      <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-search vt-w-4 vt-h-4 vt-shrink-0 vt-text-foreground-muted">
          <path d="m21 21-4.34-4.34"></path><circle cx="11" cy="11" r="8"></circle>
        </svg>
        Search
      </div>
      <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-settings vt-w-4 vt-h-4 vt-shrink-0 vt-text-foreground-muted">
          <path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"></path><circle cx="12" cy="12" r="3"></circle>
        </svg>
        Settings
      </div>
    </div>
    <div class="vt-h-[0.5px] vt-bg-border-default vt-my-1 vt--mx-1"></div>
    <div class="vt-combobox-group" data-combobox-group="">
      <div class="vt-text-xs vt-font-semibold vt-text-foreground-muted vt-px-2 vt-py-1.5">Results</div>
      <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-calculator vt-w-4 vt-h-4 vt-shrink-0 vt-text-foreground-muted">
          <rect width="16" height="20" x="4" y="2" rx="2"></rect><line x1="8" x2="16" y1="6" y2="6"></line><line x1="16" x2="16" y1="14" y2="18"></line><path d="M16 10h.01"></path><path d="M12 10h.01"></path><path d="M8 10h.01"></path><path d="M12 14h.01"></path><path d="M8 14h.01"></path><path d="M12 18h.01"></path><path d="M8 18h.01"></path>
        </svg>
        Calculator
      </div>
      <div class="vt-combobox-item" onclick="selectComboboxItem(this)">

        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-user vt-w-4 vt-h-4 vt-shrink-0 vt-text-foreground-muted">
          <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle>
        </svg>
        Profile
      </div>
    </div>
    <div class="vt-combobox-empty vt-hidden vt-py-4 vt-text-center vt-text-sm vt-text-foreground-muted">No results found.</div>
  </div>
</div>

Multi-Select

Select multiple items with tags displayed in the input area.

html
React Vue
React
Vue
Angular
Svelte
Solid
No results found.
<div class="vt-w-80 vt-relative vt-combobox-wrapper" data-multi="true">
  <div class="vt-combobox-tags vt-flex vt-flex-wrap vt-items-center vt-gap-1.5 vt-min-h-[2.5rem] vt-w-full vt-rounded-lg vt-border vt-border-border-strong vt-bg-surface-card vt-px-3 vt-py-1.5 vt-cursor-text vt-focus-within:ring-1 vt-focus-within:ring-info-fill" onclick="this.querySelector('input').focus(); openCombobox('cb-multi')">
    <span class="vt-combobox-tag vt-inline-flex vt-items-center vt-gap-1 vt-rounded vt-bg-surface-subtle vt-px-2 vt-py-0.5 vt-text-xs vt-font-medium" data-tag-value="React">
      React
      <button type="button" onclick="event.stopPropagation(); removeComboboxTag(this)" class="vt-ml-0.5 vt-rounded-sm vt-hover:bg-surface-moderate vt-transition-colors"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="vt-w-3 vt-h-3"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button>
    </span>
    <span class="vt-combobox-tag vt-inline-flex vt-items-center vt-gap-1 vt-rounded vt-bg-surface-subtle vt-px-2 vt-py-0.5 vt-text-xs vt-font-medium" data-tag-value="Vue">
      Vue
      <button type="button" onclick="event.stopPropagation(); removeComboboxTag(this)" class="vt-ml-0.5 vt-rounded-sm vt-hover:bg-surface-moderate vt-transition-colors"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="vt-w-3 vt-h-3"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button>
    </span>
    <input type="text" onfocus="openCombobox('cb-multi')" oninput="filterCombobox(this, 'cb-multi')" class="vt-flex-1 vt-min-w-[40px] vt-bg-transparent vt-text-sm vt-outline-none vt-placeholder:text-foreground-muted" aria-label="Value">
  </div>
  <div id="cb-multi" class="vt-dropdown-menu vt-w-full vt-mt-1" data-combobox-content="">
    <div class="vt-combobox-item vt-selected" onclick="toggleMultiComboboxItem(this)">

      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="vt-w-4 vt-h-4 vt-shrink-0 vt-text-info-fill vt-combobox-icon"><path d="M20 6 9 17l-5-5"></path></svg>
      React
    </div>
    <div class="vt-combobox-item vt-selected" onclick="toggleMultiComboboxItem(this)">

      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="vt-w-4 vt-h-4 vt-shrink-0 vt-text-info-fill vt-combobox-icon"><path d="M20 6 9 17l-5-5"></path></svg>
      Vue
    </div>
    <div class="vt-combobox-item" onclick="toggleMultiComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Angular
    </div>
    <div class="vt-combobox-item" onclick="toggleMultiComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Svelte
    </div>
    <div class="vt-combobox-item" onclick="toggleMultiComboboxItem(this)">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Solid
    </div>
    <div class="vt-combobox-empty vt-hidden vt-py-4 vt-text-center vt-text-sm vt-text-foreground-muted">No results found.</div>
  </div>
</div>

With Button Trigger

Combobox with a button trigger instead of an input field.

html
Backlog
Todo
In Progress
Done
Cancelled
<div class="vt-w-56 vt-relative vt-combobox-wrapper">
  <button type="button" onclick="toggleCombobox('cb-button')" class="vt-input vt-items-center vt-justify-between vt-hover:bg-surface-subtle">
    <span class="vt-combobox-button-label vt-text-foreground-muted">Select status...</span>
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-chevron-down vt-w-4 vt-h-4 vt-text-foreground-muted vt-shrink-0">
      <path d="m6 9 6 6 6-6"></path>
    </svg>
  </button>
  <div id="cb-button" class="vt-dropdown-menu vt-w-full vt-mt-1" data-combobox-content="">
    <div class="vt-combobox-item" onclick="selectComboboxButton(this, 'cb-button')">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Backlog
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxButton(this, 'cb-button')">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Todo
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxButton(this, 'cb-button')">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      In Progress
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxButton(this, 'cb-button')">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Done
    </div>
    <div class="vt-combobox-item" onclick="selectComboboxButton(this, 'cb-button')">

      <span class="vt-w-4 vt-h-4 vt-shrink-0 vt-combobox-icon"></span>
      Cancelled
    </div>
  </div>
</div>

Guidelines

Searchable select, optionally multi-value with tags. Overkill for under ~10 options → select.

Do
Use a combobox to filter and pick from a long list.
Don't
Don't use a combobox for two or three options — use a select.
React Vue
Do
Show multi-select values as removable tag chips.
React Vue
Don't
Don't hide selected multi-values with no way to remove them.

Anatomy

HTML structure of the Combobox component.

div.vt-combobox-wrapper                  ← Root (relative positioning)
├── input.vt-input                          ← Search input
└── div.vt-dropdown-menu                    ← Dropdown panel
    ├── div.vt-combobox-group               ← Optional group
    │   ├── div (label)                    ← Group heading
    │   └── div.vt-command-item            ← Option
    │       ├── svg / span                 ← Check icon or spacer
    │       └── text                       ← Option label
    └── div.vt-combobox-empty               ← No results message

API Reference

All CSS classes available for the Combobox component.

Class Type Description
vt-combobox-wrapper Base Root wrapper — relative positioning context
vt-combobox-item Base Individual option in the dropdown list
vt-combobox-group Modifier Groups items under a label header
vt-combobox-tags Modifier Multi-select tag container wrapping the input
vt-combobox-tag Modifier Individual tag chip in multi-select mode
vt-combobox-button-label Modifier Label text inside button-trigger variant
vt-combobox-empty Modifier Empty state message when no results match
vt-selected State Marks the currently selected item
vt-open State Shows the dropdown panel
data-multi Modifier HTML attribute on wrapper — enables multi-select mode
data-keep-icons Modifier HTML attribute — preserves icons on selection

Accessibility

Keyboard and screen reader support.

Feature Details
Focus Dropdown opens on input focus, closes on click outside
Keyboard Type to filter options in real-time
Selection Click to select — checkmark icon indicates current selection
Multi-select Tags display selected items, X button removes them
Empty state Shows "No results found" when filter matches nothing