Combobox

The Combobox component is a select box you can type in. It filters as you type, holds one value or many, groups its options, and can fetch them from your server. Use the plain Select when the list is short and needs no search.

Example

Pass the options as items and bind a value. Plain strings are the quickest way to start.

value: Bangladesh

Svelte
<script>
  import { Combobox } from "theui-svelte";

  const countries = ["Bangladesh", "Brazil", "Canada", "Denmark"]
  let country = $state("Bangladesh")
</script>

<Combobox items={countries} bind:value={country} placeholder="Pick a country">
  Country
</Combobox>

Option Objects

An option can also be an object with a value, the text to show, a disabled flag and a group name. The value is what you get back; the text is what the user reads and searches.

Guest is disabled
Svelte
<script>
  const roles = [
    { value: "admin", text: "Administrator", group: "Staff" },
    { value: "editor", text: "Editor", group: "Staff" },
    { value: "member", text: "Member", group: "Public" },
    { value: "guest", text: "Guest", group: "Public", disabled: true },
  ]
</script>

<Combobox items={roles} placeholder="Choose a role">Role</Combobox>

Multiple Selection

Add multiple and the value becomes an array. Each choice is shown as a chip with its own remove button, and Backspace in an empty field removes the last one.

Svelte

value: ["Svelte"]

Svelte
<script>
  let frameworks = $state(["Svelte"])
</script>

<Combobox
  items={["Svelte", "React", "Vue", "Solid"]}
  bind:value={frameworks}
  multiple
  placeholder="Pick a few"
>Frameworks</Combobox>

Creating Options

With creatable, anything typed that does not match an option can be added as a new one. Use createText to reword the entry that offers it.

value: []

Svelte
<Combobox
  items={["Design", "Engineering", "Marketing"]}
  bind:value={tags}
  multiple
  creatable
  createText={(q) => `Add "${q}"`}
>Tags</Combobox>

Custom Options

The option snippet takes over how each row is drawn, and is handed the option itself, so a row can hold an avatar, a description or a badge.

Svelte
<Combobox items={roles} placeholder="Choose a role">
  Rich options
  {#snippet option(item)}
    <Avatar size="xs" name={item.text} />
    <span class="grow">{item.text}</span>
    <span class="text-xs text-muted">{item.group}</span>
  {/snippet}
</Combobox>

In a Form

Give the component a name to submit the value. A multiple combobox submits one field for each choice, the way a multiple select does.

Svelte
<form method="POST">
  <Combobox items={countries} name="country" value="Brazil">Country</Combobox>
  <button>Save</button>
</form>

Animation Speed

The animationSpeed prop sets how quickly the field and its panel react to focus, hover and opening. It takes "none", "slower", "slow", "normal", "fast" and "faster", and the default is "normal". Inside a Form or a Fieldset the value is inherited, so one setting covers every field at once.

Svelte
<Combobox items={countries} animationSpeed="slower" placeholder="Slower" />
<Combobox items={countries} animationSpeed="normal" placeholder="Normal" />
<Combobox items={countries} animationSpeed="faster" placeholder="Faster" />
<Combobox items={countries} animationSpeed="none" placeholder="No animation" />

Reset Styles

Set reset to true to drop the border, background and focus ring of the field and keep only the classes you pass. The chips and the panel keep their layout, so the component still works the same way. The default is false, and a Form or a Fieldset can set it for every field it holds.

Svelte
<Combobox
  items={countries}
  reset
  fieldClasses="w-full border-b-2 border-gray-400 px-1 py-2"
  placeholder="Underline only" />

Customization

Sizes and variants come from the Form or the Fieldset, or from the props here. Use fieldClasses for the box, panelClass for the list, optionClass for each row and chipClasses for the chips.

Brazil Canada
Svelte
<Combobox items={countries} size="lg" variant="flat" placeholder="Flat and large" />
<Combobox items={countries} rounded="full" placeholder="Fully rounded" />
<Combobox items={countries} multiple chipClasses="bg-brand-500 text-on-brand" />

Keyboard

The down arrow opens the list and moves through it, the up arrow moves back, and both wrap around. Enter takes the highlighted option, Escape closes the list and keeps the focus, Home and End jump to the first and last option, and Tab closes the list and moves on. In a multiple combobox, Backspace on an empty field removes the last chip. Disabled options are skipped.

Accessibility

The component follows the WAI-ARIA combobox pattern. The field is a text input with role="combobox" that says whether the list is open and which list it controls; the list is a listbox whose options carry their selected state, and in a multiple combobox the listbox is marked as allowing several. Focus never leaves the input: the highlighted option is pointed at with aria-activedescendant, so typing and moving through the list stay in one place. The chips of a multiple combobox each have a remove button named after the option, such as "Remove Svelte", and the clear button has its own name. The list is placed with a fixed strategy, so it flips and shifts to stay on screen instead of being cut off inside a scrolling box.

Configuration