SvTreeSelect
A single-select dropdown that shows an indented, collapsible tree in its panel - the cascader / tree-select pattern. Pick a node from a hierarchy, optionally showing its full path in the trigger.
SvTreeSelect covers hierarchical choice (a category, a folder, an org unit)
without pulling in the full SvTree. It supports bind:value,
tracks its own expand/collapse state (seeded from expandedIds), and flattens the
visible nodes for a roving-focus keyboard model where ArrowRight / ArrowLeft
expand and collapse branches. The panel portals out of any scroll container and
colors follow the grid's --sg-* tokens.
Basic usage
<script lang="ts">
import { SvTreeSelect, type TreeSelectNode } from '@svgrid/grid'
const nodes: TreeSelectNode[] = [
{ value: 'eng', label: 'Engineering', children: [
{ value: 'fe', label: 'Frontend' },
{ value: 'be', label: 'Backend' },
] },
{ value: 'design', label: 'Design' },
]
let value = $state<string | number | null>(null)
</script>
<SvTreeSelect label="Team" {nodes} bind:value showPath />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
nodes |
ReadonlyArray<TreeSelectNode> |
- | The hierarchy to choose from. |
value |
string | number | null |
null |
The selected node's value. Bindable (bind:value). |
onChange |
(value: string | number) => void |
- | Fires with the picked node's value. |
onCommit |
(value: string | number) => void |
- | Fires when a node is committed. |
onCancel |
() => void |
- | Fires when the panel is dismissed. |
placeholder |
string |
'Select…' |
Shown when nothing is selected. |
showPath |
boolean |
false |
Show the full node path (A / B / C) in the trigger. |
expandedIds |
ReadonlyArray<string | number> |
[] |
Node values expanded on first open. |
size |
sm | md | lg |
md |
Trigger height and font size. |
disabled |
boolean |
false |
Blocks interaction. |
label |
string |
- | Visible field label, wired to the control. |
hint |
string |
- | Helper text under the control. |
error |
string |
- | Error message; announced and styled when set. |
required |
boolean |
false |
Marks the field required. |
invalid |
boolean |
false |
Applies the invalid state. |
name |
string |
- | Emits a hidden input carrying the value for form posts. |
dir |
ltr | rtl | auto |
auto |
Text direction. |
ariaLabel |
string |
- | Accessible name when there is no visible label. |
id |
string |
- | Root id; label/hint/error ids derive from it. |
TreeSelectNode
type TreeSelectNode = {
value: string | number
label: string
children?: TreeSelectNode[]
disabled?: boolean
}
Patterns
Full-path trigger
Turn on showPath so the trigger reads Engineering / Frontend instead of just
the leaf label - useful when leaf names repeat across branches.
Pre-expanded branches
Seed the open state so users land deep in the tree without clicking down to it:
<SvTreeSelect {nodes} bind:value expandedIds={['eng']} />
Disabled branches
Set disabled on a node to make it unpickable while still showing (and expanding)
its children.
Build the tree from flat rows
Hierarchies usually arrive flat (a parentId column). Fold them into
TreeSelectNode[] once, then bind the selected leaf:
<script lang="ts">
import { SvTreeSelect, type TreeSelectNode } from '@svgrid/grid'
const flat = [
{ id: 'eng', parent: null, name: 'Engineering' },
{ id: 'fe', parent: 'eng', name: 'Frontend' },
{ id: 'be', parent: 'eng', name: 'Backend' },
{ id: 'design', parent: null, name: 'Design' },
]
function toTree(parent: string | null): TreeSelectNode[] {
return flat
.filter((r) => r.parent === parent)
.map((r) => ({ value: r.id, label: r.name, children: toTree(r.id) }))
}
const nodes = toTree(null)
let value = $state<string | number | null>(null)
</script>
<SvTreeSelect label="Team" {nodes} bind:value showPath />
Tip:
expandedIdsonly seeds the open branches for the first open; after that the component tracks its own expand/collapse state, so you do not have to keep the prop in sync.
Accessibility
- The panel is a
role="tree"ofrole="treeitem"rows witharia-expandedandaria-selected; the active row is tracked viaaria-activedescendant. ArrowUp/ArrowDownmove,ArrowRight/ArrowLeftexpand / collapse,Enterpicks a leaf,Escapedismisses, and focus returns to the trigger.label,hint, anderrorare wired viaaria-describedby; passariaLabelwhen there is no visible label.
See also
- Selection overview - the whole picker family at a glance.
- SvDropDownList - a flat single-select dropdown.
- SvGridSelect - pick a row across multiple columns.