Selection controls

List and overlay pickers: SvListBox (inline multi-select), SvDropDownList, SvComboBox (type to filter), SvAutoComplete (free text + suggestions), SvTagsInput (chips) and SvCountryInput (searchable, flags). Every popover portals out of the scroll container. Grid cell editors, standalone too.

A live, editable Svelte 5 component example from the SvGrid gallery (Selection). Read the SvGrid UI component docs for the full API.

About this example

The list and overlay pickers of the SvGrid UI kit in Svelte 5: SvListBox as an inline multi-select, SvDropDownList, SvComboBox that filters as you type, SvAutoComplete for free text with suggestions, SvTagsInput for chips and SvCountryInput with flags and dial codes. Every popover portals out of the scroll container so it never clips, all theme from the --sg-* tokens, and each is also a grid cell editor.

Selection controls - the SvGrid UI kit's list & overlay pickers. All share the portal engine so their popovers never clip, and theme from --sg-*.

Imports, features and API used

Imports: @svgrid/grid

Frequently asked questions

When do I use a combo box versus an autocomplete?

SvComboBox requires a value from its options and reverts unmatched text; SvAutoComplete accepts any text and treats suggestions as shortcuts. Pick by whether free text is valid input.

Why do the popovers portal?

A list that opens inside a scrolling or overflow-hidden container would be clipped. Portalling to the body and positioning next to the trigger avoids that, and the shared dismiss layer closes it on outside click or Escape.

Do they share option shapes?

Yes. options is an array of strings or { value, label } objects, optionally grouped, across the list box, dropdown and combo box.

Related documentation

Related articles

Source code (255-selection.svelte)

<script lang="ts">
  /**
   * Selection controls - the SvGrid UI kit's list & overlay pickers. All share
   * the portal engine so their popovers never clip, and theme from --sg-*.
   */
  import { SvListBox, SvDropDownList, SvComboBox, SvAutoComplete, SvTagsInput, SvCountryInput } from '@svgrid/grid'

  const fruit = [
    { value: 'apple', label: 'Apple' }, { value: 'banana', label: 'Banana' },
    { value: 'cherry', label: 'Cherry' }, { value: 'date', label: 'Date' },
    { value: 'elderberry', label: 'Elderberry' }, { value: 'fig', label: 'Fig', disabled: true },
    { value: 'grape', label: 'Grape' },
  ]
  const frameworks = ['Svelte', 'SvelteKit', 'React', 'Vue', 'Angular', 'Solid', 'Qwik', 'Astro']

  let picked = $state<string[]>(['apple'])
  let ddl = $state<string | null>('banana')
  let combo = $state<string | null>(null)
  let ac = $state('')
  let tags = $state<string[]>(['grid', 'svelte'])
  let country = $state<string | null>('US')
</script>

<div class="wrap">
  <header>
    <h2>Selection controls</h2>
    <p>List and overlay pickers from <code>@svgrid/grid</code>. Every popover portals out of the scroll container, and all are keyboard-accessible.</p>
  </header>

  <div class="grid">
    <div class="cell">
      <label>SvListBox <span class="muted">(inline, multi-select)</span></label>
      <SvListBox options={fruit} value={picked} multiple onChange={(v) => (picked = v)} rows={5} />
      <code class="out">{picked.join(', ') || '-'}</code>
    </div>

    <div class="col">
      <div class="cell">
        <label>SvDropDownList</label>
        <SvDropDownList options={fruit} value={ddl} onChange={(v) => (ddl = String(v))} />
      </div>
      <div class="cell">
        <label>SvComboBox <span class="muted">(type to filter)</span></label>
        <SvComboBox options={fruit} value={combo} onChange={(v) => (combo = v as string)} />
      </div>
      <div class="cell">
        <label>SvAutoComplete <span class="muted">(free text + suggestions)</span></label>
        <SvAutoComplete value={ac} suggestions={frameworks} onChange={(v) => (ac = v)} placeholder="Type a framework…" />
      </div>
      <div class="cell">
        <label>SvTagsInput</label>
        <SvTagsInput value={tags} onChange={(t) => (tags = t)} />
      </div>
      <div class="cell">
        <label>SvCountryInput <span class="muted">(searchable, flags)</span></label>
        <SvCountryInput value={country} showDial onChange={(v) => (country = v)} />
      </div>
    </div>
  </div>
</div>

<style>
  .wrap { padding: 22px; max-width: 820px; display: flex; flex-direction: column; gap: 18px; }
  header h2 { margin: 0 0 4px; font-size: 20px; font-weight: 700; }
  header p { margin: 0; color: var(--sg-muted, #64748b); font-size: 13.5px; max-width: 620px; }
  code { background: var(--sg-row-hover-bg, #eef2ff); padding: 1px 5px; border-radius: 5px; font-size: 12px; }
  .grid { display: flex; gap: 40px; flex-wrap: wrap; align-items: flex-start; }
  .col { display: flex; flex-direction: column; gap: 16px; }
  .cell { display: flex; flex-direction: column; gap: 7px; align-items: flex-start; }
  label { font-size: 12.5px; font-weight: 600; }
  .muted { color: var(--sg-muted, #64748b); font-weight: 400; }
  .out { align-self: stretch; }
</style>

View this example on GitHub

More Selection examples

  • List box - SvListBox: an assignee picker - inline multi-select with grouped options (departments), roving keyboard + type-ahead and a live summary.
  • Combo box - SvComboBox: a form field - type to filter a grouped, portalled list; the value must come from the list. With label + required validation.
  • Drop-down list - SvDropDownList: a status / priority toolbar with grouped options, type-ahead and animated portalled panels driving a live issue list.
  • Autocomplete - SvAutoComplete: a free-text search field with live suggestion shortcuts (any value accepted) - city search and a filter-syntax helper.
  • Resizable dropdowns - Built-in browser bounds detection - every picker panel (SvDropDownList / SvComboBox / SvAutoComplete) opens downward when there is room and flips upward automatically near the window edge. Plus a `resizable` prop that adds a bottom drag grip to the open panel (drag to grow/shrink; height sticks for the session; grip hides on an upward flip). A switch compares fixed-height vs resizable. Theme-aware (light/dark).