Skip to content

Inputs

Combobox

Select with built-in search for long option lists.

<script>
  import { Combobox } from "@codeatlasdev/ui";
  let value = $state("");
</script>

<Combobox label="Framework" options={[{ value: "svelte", label: "Svelte" }]} bind:value />

Typing in the popup filters options by label, and opening the list moves focus to the search input. Pass a label (or ariaLabel) so the trigger and listbox have an accessible name. It has no name prop and does not submit with a native form (unlike Select): read value instead.

#010

Basic

Search a list of options and bind the selected value.

Reference #010 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Combobox } from '@codeatlasdev/ui';

  const frameworks = [
    { value: 'svelte', label: 'Svelte' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue' },
    { value: 'angular', label: 'Angular' },
    { value: 'solid', label: 'SolidJS' },
    { value: 'astro', label: 'Astro' },
    { value: 'nuxt', label: 'Nuxt' },
    { value: 'sveltekit', label: 'SvelteKit' },
  ];

  let selected = $state('');
</script>

<div class="col">
  <Combobox label="Framework" options={frameworks} bind:value={selected} />
  {#if selected}
    <p class="out">Selected: <code>{selected}</code></p>
  {/if}
</div>

<style>
  .col {
    width: 100%;
    max-width: 320px;
  }

  .out {
    margin: var(--ca-space-3) 0 0;
    font-size: var(--ca-font-size-body2);
    color: var(--ca-text-secondary);
  }
</style>
#011

States

Description, custom search placeholder and empty text, disabled option, error and disabled.

Astro is disabled.

Reference #011 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Combobox } from '@codeatlasdev/ui';

  const frameworks = [
    { value: 'svelte', label: 'Svelte' },
    { value: 'react', label: 'React' },
    { value: 'vue', label: 'Vue' },
    { value: 'astro', label: 'Astro', disabled: true },
  ];

  let value = $state('');
</script>

<div class="col">
  <Combobox
    label="Framework"
    options={frameworks}
    bind:value
    description="Astro is disabled."
    searchPlaceholder="Filter frameworks…"
    emptyText="No framework matches."
  />
  <Combobox label="Framework" options={frameworks} error="Pick a framework." required />
  <Combobox label="Framework" options={frameworks} disabled placeholder="Unavailable" />
</div>

<style>
  .col {
    display: flex;
    flex-direction: column;
    gap: var(--ca-space-4);
    width: 100%;
    max-width: 320px;
  }
</style>

Multiple selection

Set multiple and bind value to a string[]. The popup becomes a listbox with aria-multiselectable, each pick toggles its option (aria-selected) and the list stays open so you can keep picking. Selected values show as removable chips above the trigger, and the trigger shows the count. With the search input focused, Enter toggles the highlighted option and Backspace on an empty query removes the last chip.

Add creatable to offer a Create "text" row when the query matches no option exactly. Choosing it appends the text to value and calls oncreate(text): add it to options there if you want it to stay selectable. In single mode creatable sets value to the new text and closes the list.

#420

Multiple

Searchable multi-select with removable chips and a disabled option.

Bug UI

Backspace on an empty search removes the last chip.

Selected: bug, ui

Reference #420 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Combobox } from '@codeatlasdev/ui';

  const labels = [
    { value: 'bug', label: 'Bug' },
    { value: 'docs', label: 'Documentation' },
    { value: 'ui', label: 'UI' },
    { value: 'a11y', label: 'Accessibility' },
    { value: 'perf', label: 'Performance' },
    { value: 'legacy', label: 'Legacy', disabled: true },
  ];

  let selected = $state<string[]>(['bug', 'ui']);
</script>

<div class="col">
  <Combobox
    multiple
    label="Labels"
    description="Backspace on an empty search removes the last chip."
    options={labels}
    bind:value={selected}
  />
  <p class="out">Selected: <code>{selected.join(', ') || 'none'}</code></p>
</div>

<style>
  .col {
    width: 100%;
    max-width: 360px;
  }

  .out {
    margin: var(--ca-space-3) 0 0;
    font-size: var(--ca-font-size-body2);
    color: var(--ca-text-secondary);
  }
</style>
#421

Creatable tags

Create a tag from the search text when nothing matches.

Reference #421 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Combobox } from '@codeatlasdev/ui';

  let options = $state([
    { value: 'design', label: 'design' },
    { value: 'backend', label: 'backend' },
    { value: 'urgent', label: 'urgent' },
  ]);
  let tags = $state<string[]>([]);

  function onCreate(value: string) {
    options = [...options, { value, label: value }];
  }
</script>

<div class="col">
  <Combobox
    multiple
    creatable
    label="Tags"
    placeholder="Add tags"
    searchPlaceholder="Search or create a tag"
    {options}
    bind:value={tags}
    oncreate={onCreate}
  />
</div>

<style>
  .col {
    width: 100%;
    max-width: 360px;
  }
</style>

Props

PropTypeDefaultDescription
valuestring | string[]'' (or [] when multiple)Bindable selected value. A `string[]` when `multiple` is set.
multiplebooleanfalseMulti-select: `value` is `string[]`, the list stays open after each pick, selections render as removable chips.
creatablebooleanfalseOffers a `Create "query"` row when the query matches no option label exactly.
oncreate(value: string) => void–Called with the new text when the create row is chosen.
optionsComboboxOption[]–Options: { value, label, disabled? }.
labelstring–Visible label above the trigger.
ariaLabelstring–Accessible name when there is no visible `label`. The trigger is named `ariaLabel` followed by its current value. Without either, it is named only by its current value.
placeholderstring'Select…' (localized)Trigger text when nothing is selected. Default comes from the active i18n catalog.
searchPlaceholderstring'Search…' (localized)Placeholder and accessible name of the search input.
emptyTextstring'No results' (localized)Message shown when the filter matches nothing.
descriptionstring–Hint shown below the trigger.
errorstring–Error message. Puts the combobox in the error state.
requiredbooleanfalseMarks the field as required.
disabledbooleanfalseDisables the combobox.
size'sm' | 'md''md'Trigger height.
classstring–Extra classes on the root.
onchange(value: string | string[]) => void–Called when the selection changes. Receives the array when `multiple`.