elements
Demos UI Feed Discuss Install
Style System
  • Style
  • Themes
  • Behaviors
Forms
  • Button
  • ButtonGroup
  • Checkbox
  • ColorPicker
  • Combobox
  • Field
  • FileUpload
  • Input
  • InputGroup
  • InputOTP
  • Label
  • NativeSelect
  • NumberInput
  • PasswordInput
  • RadioGroup
  • Select
  • Slider
  • Switch
  • TagsInput
  • Textarea
  • Toggle
  • ToggleGroup
Overlays
  • AlertDialog
  • Command
  • ContextMenu
  • Dialog
  • Drawer
  • DropdownMenu
  • HoverCard
  • Menubar
  • NavigationMenu
  • Popover
  • Sheet
  • Toast
  • Tooltip
Display
  • Accordion
  • Alert
  • AspectRatio
  • Avatar
  • Badge
  • Breadcrumb
  • Card
  • Collapsible
  • Empty
  • Item
  • Kbd
  • Pagination
  • Progress
  • Separator
  • Skeleton
  • Spinner
  • Table
  • Tabs
  • Tree
Layout
  • Carousel
  • Resizable
  • ScrollArea
  • Sidebar
Dates
  • Calendar
  • DatePicker
  • DateRangePicker
  • TimePicker
Data
  • AreaChart
  • BarChart
  • Chart
  • DataTable
  • Kanban
  • LineChart
  • PieChart
  • RadarChart
  • RadialChart
  • VirtualList
Chat
  • Attachment
  • Message
  • MessageList
  • PromptInput
Elements UI / Forms / Combobox

Combobox

A text input that filters a list of options as you type, for one value or several shown as chips, with async results.

Basic

Type to filter, arrows to move, Enter to pick. Escape puts the selected label back.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
value: ; text: ; complete:
Code
const ANIMALS = [
  { value: "tiger", label: "Tiger" },
  { value: "koala", label: "Koala" },
  ...
];

<Combobox value={form.animal} items={ANIMALS} placeholder="Select an animal" />

Usage

import { Combobox, ComboboxItem, ComboboxGroup, ComboboxRow, ComboboxLabel, ComboboxSeparator } from "@elements/ui/combobox";

<Combobox value={form.framework} items={FRAMEWORKS} placeholder="Select a framework" label="Framework" />

<!-- several values, as chips -->
<Combobox multiple values={form.tags} placeholder="Add tags" name="tags">
  <ComboboxItem e:for={tag of TAGS} value={tag.id}>{tag.name}</ComboboxItem>
</Combobox>

<!-- async: the caller filters -->
<Combobox inputValue={search.q} filter={null} loading={search.loading} value={form.user}
          onInputValueChange={(q) => find(search, q)}>
  <ComboboxItem e:for={u of search.results} value={u.id}>{u.name}</ComboboxItem>
</Combobox>

Examples

Groups

Groups hide when none of their options match; separators hide while a query filters.

Americas
Argentina
Brazil
Canada
Chile
Mexico
United States
Europe
France
Germany
Iceland
Italy
Spain
United Kingdom
Asia
China
India
Japan
South Korea
Singapore
Vietnam
Somewhere else
No results found.
Code
<Combobox value={form.country} placeholder="Select a country">
  <ComboboxGroup e:for={g of COUNTRIES} label={g.region}>
    <ComboboxItem e:for={[code, name] of g.items} value={code}>{name}</ComboboxItem>
  </ComboboxGroup>
  <ComboboxSeparator />
  <ComboboxItem value="other">Somewhere else</ComboboxItem>
</Combobox>

Multiple

Picked values become chips on one line that scrolls sideways; chipsWrap lets them wrap. Backspace in the empty input removes the last chip; Left moves onto the chips.

bug
Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
Bug Docs Design
Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
values: bug
Code
<Combobox multiple values={form.tags} placeholder="Add labels" name="tags" label="Labels">
  <ComboboxItem e:for={tag of TAGS} value={tag}>{tag}</ComboboxItem>
</Combobox>

<Combobox multiple chipsWrap values={form.more} ...>

Keep the filter

keepInputOnPick leaves the typed text and the filtered list in place after a pick, so several matches can be picked in a row.

Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
values:
Code
<Combobox multiple keepInputOnPick values={form.tags} items={TAG_ITEMS} label="Labels" />

Chip limit

chipLimit shows the first chips and a count of the rest. Every value still submits.

Bug Feature +3 more
Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
values: bug,feature,docs,design,testing
Code
<Combobox multiple chipLimit={2} values={form.tags} items={TAG_ITEMS} name="labels" label="Labels" />

Clear button

showClear adds a button that empties the text and the selection. Its space stays reserved, so nothing moves when it appears.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
value: otter
Code
<Combobox showClear value={form.animal} items={ANIMALS} />

Auto highlight

autoHighlight keeps the first match highlighted while typing, so Enter picks it.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox autoHighlight value={form.animal} items={ANIMALS} />

Grid

grid lays the options out in ComboboxRow rows: arrows move across rows and columns, and typing filters by each cell's label.

🍎 apple
🍌 banana
🍒 cherries
🍇 grapes
🍋 lemon
🥭 mango
🍑 peach
🍐 pear
🥕 carrot
🌽 corn
🌶️ pepper
🥔 potato
No results found.
value:
Code
<Combobox grid value={form.emoji} placeholder="Find a fruit or vegetable">
  <ComboboxRow e:for={row of EMOJI_ROWS}>
    <ComboboxItem e:for={e of row} value={e.id} label={e.id}>
      <span aria-hidden="true">{e.char}</span>
      <span class="sr-only">{e.id}</span>
    </ComboboxItem>
  </ComboboxRow>
</Combobox>

Custom items

Options take any markup. label sets what the input shows, keywords add words the filter matches, and the empty slot replaces the empty text.

OM Olivia Martin Owner
JL Jackson Lee Member
IN Isabella Nguyen Member
WK William Kim Billing
Nobody by that name.
Code
<Combobox value={form.member} placeholder="Assign to">
  <ComboboxItem e:for={m of MEMBERS} value={m.id} label={m.name} keywords={m.keywords}>
    <span class="avatar">{initials(m.name)}</span>
    {m.name}
    <span class="meta">{m.role}</span>
  </ComboboxItem>
  <span slot="empty">Nobody by that name. <a href="/invite">Invite them</a></span>
</Combobox>

Async

filter={null} leaves filtering to you. Bind inputValue, fetch on change, set loading while waiting.

Ada Lovelace ada@example.com
Alan Turing alan@example.com
Barbara Liskov barbara@example.com
Donald Knuth don@example.com
No results found.
user:
Code
function find(state, q) {
  state.loading = true;
  searchUsers(q).then((users) => {      // an @rpc call
    state.results = users;
    state.loading = false;
  });
}

<Combobox value={form.user} inputValue={state.query} filter={null}
          loading={state.loading} placeholder="Search people"
          onInputValueChange={(q) => find(state, q)}>
  <ComboboxItem e:for={u of state.results} value={u.id} label={u.name}>
    {u.name} <span class="meta">{u.email}</span>
  </ComboboxItem>
</Combobox>

Async, multiple

The same search with chips. A chip keeps its label when new results no longer include its item.

Ada Lovelace ada@example.com
Alan Turing alan@example.com
Barbara Liskov barbara@example.com
Donald Knuth don@example.com
Edsger Dijkstra edsger@example.com
No results found.
people:
Code
<Combobox multiple values={form.people} inputValue={search.query} filter={null}
          loading={search.loading} placeholder="Add people"
          onInputValueChange={(q) => find(search, q)}>
  <ComboboxItem e:for={u of search.results} value={u.id} label={u.name}>
    {u.name} <span class="meta">{u.email}</span>
  </ComboboxItem>
</Combobox>

Virtualized

virtualized renders only the rows in view, so a list of 10,000 options opens and scrolls at once. Typing filters all 10,000 on the client; arrows, PageUp and PageDown still reach every option.

No results found.
value:
Code
const ITEMS = Array.from({ length: 10000 }, (_, i) => ({
  value: `item-${i + 1}`,
  label: `Item ${i + 1}`,
}));

<Combobox virtualized value={form.item} items={ITEMS} placeholder="Type to filter 10,000 items" />

Inline

inline shows the list in the page under the input, always open, with no popup. It keeps the value, the chips, the form name and the keys; the list holds one height while it filters.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
value: ; tags: ; submitted:
Code
<Combobox inline name="animal" value={form.animal} items={ANIMALS}
          label="Animal" placeholder="Filter animals" />

<Combobox inline multiple name="tags" values={form.tags} items={TAG_ITEMS}
          label="Labels" placeholder="Filter labels" />

Limit and filter

limit caps the matches shown. filter takes any matcher; startsWithFilter matches word starts and endsWithFilter the end of a label.

Argentina
Brazil
Canada
Chile
Mexico
United States
France
Germany
Iceland
Italy
Spain
United Kingdom
China
India
Japan
South Korea
Singapore
Vietnam
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox limit={3} value={form.country} items={ALL_COUNTRIES} />
<Combobox filter={startsWithFilter} items={ANIMALS} />
<Combobox filter={endsWithFilter} items={ANIMALS} />

Invalid, disabled, read only

invalid shows the danger border; in a Field the label names the input. disabled does nothing; readOnly shows the value without opening.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Pick an animal.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Field label="Animal" error={form.animal ? "" : "Pick an animal."}>
  <Combobox invalid={!form.animal} value={form.animal} items={ANIMALS} />
</Field>
<Combobox disabled value="tiger" items={ANIMALS} label="Animal" />
<Combobox readOnly value="fox" items={ANIMALS} label="Animal" />

Form

name submits the value (not the typed text); multiple submits one entry per value; required blocks an empty submit; reset restores.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Docs
Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
submitted:
Code
<form>
  <Combobox name="animal" required value={form.animal} items={ANIMALS} label="Animal" />
  <Combobox name="tags" multiple values={form.tags} items={TAG_ITEMS} label="Labels" />
  <Button type="submit">Submit</Button>
  <Button type="reset">Reset</Button>
</form>

Required, multiple

required with multiple blocks an empty submit until at least one value is picked.

Bug
Feature
Docs
Design
Performance
Security
Testing
Refactor
No results found.
submitted:
Code
<form>
  <Combobox multiple required name="labels" values={form.labels} items={LABELS} label="Labels" />
  <Button type="submit">Submit</Button>
</form>

Outside its form

form ties the value to a form the combobox sits outside of; autocomplete is the autofill hint on the submitted input.

Argentina
Brazil
Canada
Chile
Mexico
United States
France
Germany
Iceland
Italy
Spain
United Kingdom
China
India
Japan
South Korea
Singapore
Vietnam
No results found.
submitted:
Code
<form id="shipping" onsubmit={save}>
  <Button type="submit">Save</Button>
</form>
<Combobox form="shipping" name="country" autocomplete="country-name"
          value={form.country} items={COUNTRIES} />

Disabled options

A disabled option is shown but the arrows skip it and a click does not pick it.

Hobby
Pro
Team
Business
Enterprise
No results found.
plan:
Code
<Combobox value={form.plan} items={[
  { value: "hobby", label: "Hobby" },
  { value: "team", label: "Team", disabled: true },
  ...
]} />

<!-- or on an item -->
<ComboboxItem value="team" disabled>Team</ComboboxItem>

Input addon

slot="start" puts an icon or text inside the input chrome, before the text, without changing the control's height.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox value={form.animal} items={ANIMALS} placeholder="Search animals">
  <Icon slot="start" name="search" />
</Combobox>

Input inside popup

inputInPopup puts the search in the popup and a button in the page that shows the value, like a select you can type in. The value still submits under name.

Argentina
Brazil
Canada
Chile
Mexico
United States
France
Germany
Iceland
Italy
Spain
United Kingdom
China
India
Japan
South Korea
Singapore
Vietnam
No results found.
submitted:
Code
<form>
  <Combobox inputInPopup name="country" value={form.country} items={COUNTRIES}
            placeholder="Select a country" searchPlaceholder="Search countries..." />
</form>

Controlled

Bind value, inputValue and open. The callbacks report only what the combobox did.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
value: tiger; text: ; open: false; changes: ; opens: highlights:
Code
<Combobox value={state.animal} inputValue={state.text} open={state.open}
          items={ANIMALS} label="Animal"
          onValueChange={(v) => log(v)}
          onInputValueChange={(t) => log(t)}
          onOpenChange={(o) => log(o)}
          onItemHighlighted={(v) => log(v)} />

Change details

onValueChange, onInputValueChange and onOpenChange get change details as a second argument: the reason (input-press, item-press, input-change, escape-key, clear-press), the event and cancel().

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox value={form.animal} items={ANIMALS}
          onValueChange={(value, details) => log(value, details.reason)}
          onOpenChange={(open, details) => log(open, details.reason)} />

Object values

A value can be an object. isItemEqualToValue matches the bound value to its item, itemToStringLabel shows it in the input and itemToStringValue submits it. items also takes a record of value to label, or groups.

Ada Lovelace
Grace Hopper
Alan Turing
No results found.
Apple
Banana
Cherry
No results found.
Grace Hopper #2
Code
<Combobox value={form.person}
          items={PEOPLE.map((person) => ({ value: person }))}
          isItemEqualToValue={(item, value) => item.id === value.id}
          itemToStringLabel={(person) => person.name}
          itemToStringValue={(person) => String(person.id)}
          name="person" />

<Combobox items={{ apple: "Apple", banana: "Banana" }} />      <!-- a record of value to label -->

Anchor and boundary

anchor places the popup against another element than the input, and collisionBoundary keeps it inside an element's edges as well as the viewport.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Anchor
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<span id="animal-anchor">Anchor</span>
<Combobox anchor="#animal-anchor" ...>                     <!-- placed against another element -->

<div class="box">
  <Combobox collisionBoundary=".box" ...>                     <!-- flips and shrinks to stay in the box -->
</div>

Options

openOnInputClick={false} opens only from the keyboard or the chevron, here hidden with showTrigger={false}. highlightItemOnHover={false} leaves the highlight to the keyboard. modal locks the page while open; sideOffset and alignOffset move the popup; items with a group field render grouped. value, open and inputValue with no binding set where it starts.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Web
TypeScript
JavaScript
CSS
Systems
Go
Rust
Zig
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox openOnInputClick={false} showTrigger={false} items={ANIMALS} />  <!-- a click does not open; no chevron -->
<Combobox highlightItemOnHover={false} items={ANIMALS} />                  <!-- the pointer does not move the highlight -->
<Combobox modal sideOffset={8} alignOffset={4} items={LANGUAGES} />            <!-- items with group; scroll locked while open -->
<Combobox value="otter" items={ANIMALS} />                                 <!-- unbound: the first value -->
<Combobox open={true} inputValue="ot" items={ANIMALS} />                   <!-- unbound: open and filtered when it mounts -->

Positioning

arrow points at the input from the popup's edge, and arrowPadding keeps it off the corners. collisionAvoidance chooses whether the popup flips or shifts. sticky keeps it in view after the input scrolls away. disableAnchorTracking places it when it opens and on a scroll or resize, not when the page shifts under it. backdrop puts an overlay under it.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox arrow side="top" sideOffset={10} items={ANIMALS} />               <!-- an arrow on the edge facing the input -->
<Combobox arrow arrowPadding={12} alignOffset={160} items={ANIMALS} />     <!-- the arrow keeps 12px from the corner -->
<Combobox collisionAvoidance={{ side: "none" }} items={ANIMALS} />          <!-- never flips; shrinks instead -->
<Combobox sticky items={ANIMALS} />                                         <!-- stays in view after the input scrolls away -->
<Combobox disableAnchorTracking items={ANIMALS} />                          <!-- placed on open, on scroll and on resize only -->
<Combobox backdrop items={ANIMALS} />                                       <!-- an overlay under the popup -->

Locale

locale sets the case rules the filter folds by. In Turkish, ı and i are different letters: type ı to find Isparta and Iğdır, i to find İstanbul and İzmir.

İstanbul
İzmir
Isparta
Iğdır
Ankara
No results found.
İstanbul
İzmir
Isparta
Iğdır
Ankara
No results found.
Code
<Combobox locale="tr" items={CITIES} />   <!-- Turkish case rules: i and dotless ı are different letters -->

Sizes

size follows the control height tokens.

Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Tiger
Koala
Badger
Otter
Fox
Turtle
No results found.
Code
<Combobox size="sm" ... />
<Combobox size="lg" ... />

RTL

In a right-to-left region the buttons sit on the left and the check on the left of each option.

نمر
كوالا
ثعلب
قضاعة
No results found.
Code
<Combobox dir="rtl" placeholder="اختر حيوانا" showClear
          clearLabel="مسح" triggerLabel="عرض الخيارات" removeLabel="إزالة" ...>
  <ComboboxItem value="tiger">نمر</ComboboxItem>
  ...
</Combobox>
Reference Combobox in the manual Every part, attribute, slot, key and data attribute.
Prev ColorPickerNext Field
Product
Manual Pricing Compare
Company
History Contact
Legal
Privacy Policy Acceptable Use Terms License Agreement
© Elements Dev Corporation 2026