Tree select

SvTreeSelect: a single-select dropdown showing a collapsible tree in its portalled panel (the tree-select / cascader pattern). Arrow keys navigate, Right/Left expand/collapse, Enter selects; optional full-path label in the trigger.

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

SvTreeSelect in Svelte 5, a single-select dropdown that shows a collapsible tree in its portalled panel, the tree-select or cascader pattern. Arrow keys navigate, Right and Left expand and collapse, Enter selects, expandedIds sets the initial open branches and showPath prints the full path in the trigger. Standalone or a grid cell editor.

SvTreeSelect - a single-select dropdown that shows a collapsible tree in its panel (the "tree select / cascader" pattern). Built on its own portalled panel via the shared primitives, standalone or as a grid cell editor.

Imports, features and API used

Imports: @svgrid/grid

Frequently asked questions

How are the nodes defined?

As a nodes array of { id, label, children } objects nested as deep as needed. A node with disabled set is shown but cannot be picked.

What is shown after a pick?

The node's label, or with showPath the whole path such as Asia, Japan, Tokyo, which helps when leaf names repeat across branches.

How do I open branches by default?

Pass expandedIds with the ids to start open; the panel also remembers what the user expanded while it stays mounted.

Related documentation

Related articles

Source code (335-tree-select.svelte)

<script lang="ts">
  /**
   * SvTreeSelect - a single-select dropdown that shows a collapsible tree in its
   * panel (the "tree select / cascader" pattern). Built on its own portalled
   * panel via the shared primitives, standalone or as a grid cell editor.
   */
  import { SvTreeSelect, SvCheckBox, type TreeSelectNode } from '@svgrid/grid'

  const places: TreeSelectNode[] = [
    { value: 'asia', label: 'Asia', children: [
      { value: 'jp', label: 'Japan', children: [
        { value: 'tokyo', label: 'Tokyo' },
        { value: 'osaka', label: 'Osaka' },
      ] },
      { value: 'cn', label: 'China', children: [
        { value: 'beijing', label: 'Beijing' },
        { value: 'shanghai', label: 'Shanghai' },
      ] },
    ] },
    { value: 'eu', label: 'Europe', children: [
      { value: 'fr', label: 'France', children: [{ value: 'paris', label: 'Paris' }] },
      { value: 'de', label: 'Germany', children: [{ value: 'berlin', label: 'Berlin' }] },
    ] },
    { value: 'na', label: 'North America', children: [
      { value: 'us', label: 'United States', children: [
        { value: 'nyc', label: 'New York' },
        { value: 'sf', label: 'San Francisco' },
      ] },
    ] },
  ]

  let city = $state<string | number | null>('tokyo')
  let showPath = $state(true)
</script>

<div class="wrap">
  <header>
    <h2>Tree select</h2>
    <p>Pick a node from a hierarchy. Arrow keys navigate, Right/Left expand/collapse, Enter selects. The panel portals to <code>&lt;body&gt;</code> so it is never clipped.</p>
  </header>

  <div class="row">
    <SvTreeSelect
      label="City"
      nodes={places}
      value={city}
      onChange={(v) => (city = v)}
      expandedIds={['asia', 'jp']}
      {showPath}
    />
    <SvCheckBox checked={showPath} onChange={(v) => (showPath = v)}>Show full path in trigger</SvCheckBox>
  </div>

  <p class="muted">Selected value: <code>{city ?? '(none)'}</code></p>
</div>

<style>
  .wrap { padding: 20px; max-width: 720px; 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; line-height: 1.5; }
  header code, .muted code { background: var(--sg-row-hover-bg, #f1f5f9); padding: 1px 5px; border-radius: 4px; font-size: 12px; }
  .row { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
  .muted { color: var(--sg-muted, #64748b); font-size: 13px; }
</style>

View this example on GitHub

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