List box

SvListBox: an assignee picker - inline multi-select with grouped options (departments), roving keyboard + type-ahead and a live summary.

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

What this example shows

SvListBox - a production assignee picker: an inline multi-select list with grouped options (departments) and a live selection summary. Copy-paste ready.

Imports, features and API used

Imports: @svgrid/grid

Source code (312-listbox.svelte)

<script lang="ts">
  /**
   * SvListBox - a production assignee picker: an inline multi-select list with
   * grouped options (departments) and a live selection summary. Copy-paste ready.
   */
  import { SvListBox } from '@svgrid/grid'
  import type { ListOption } from '@svgrid/grid'

  const people: ListOption[] = [
    { value: 'amy', label: 'Amy Chen', group: 'Engineering' },
    { value: 'ben', label: 'Ben Ortiz', group: 'Engineering' },
    { value: 'cara', label: 'Cara Singh', group: 'Engineering' },
    { value: 'dan', label: 'Dan Weber', group: 'Design' },
    { value: 'eve', label: 'Eve Larsson', group: 'Design' },
    { value: 'finn', label: 'Finn Murphy', group: 'Product' },
    { value: 'gia', label: 'Gia Rossi', group: 'Product' },
  ]
  let assignees = $state<Array<string | number>>(['amy', 'dan'])
  const names = $derived(assignees.map((v) => people.find((p) => p.value === v)?.label).join(', '))
</script>

<div class="wrap">
  <header>
    <h2>List box</h2>
    <p>An inline single/multi-select list (WAI-ARIA listbox) with grouped options, roving keyboard and type-ahead. Assign work, build audiences, pick columns.</p>
  </header>

  <div class="card">
    <label class="ttl">Assignees</label>
    <SvListBox options={people} value={assignees} multiple rows={7} onChange={(v) => (assignees = v)} />
    <p class="summary">{assignees.length ? names : 'No one assigned'}</p>
  </div>
</div>

<style>
  .wrap { padding: 20px; max-width: 420px; display: flex; flex-direction: column; gap: 16px; }
  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; line-height: 1.5; }
  .card { display: flex; flex-direction: column; gap: 8px; }
  .ttl { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--sg-muted, #64748b); }
  .summary { margin: 0; font-size: 13px; color: var(--sg-fg, #0f172a); }
</style>

View this example on GitHub

Related documentation

Related articles

More Selection examples

  • 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.
  • 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).