Tree
2 partsA hierarchical list of expandable/collapsible nodes with full keyboard
support. Use it to present nested data — file explorers, navigation
sidebars, category pickers, or any place users drill into parent/child
relationships. Works with either nested or flat source data via the
getKey / getChildren accessors.
The root owns selection state (single or multiple, controlled via
v-model or uncontrolled via defaultValue), expanded state
(v-model:expanded), roving focus and arrow/Home/End navigation, and
exposes the computed visible flatItems through its default slot for
each TreeItem to render.
Demo
Anatomy
Import the parts and compose them. Each part forwards attributes to its underlying element.
import {
TreeRoot,
TreeItem,
} from '@robonen/primitives/navigation/tree';
<TreeRoot>
<TreeItem />
</TreeRoot>API Reference
TreeRoot
RootA hierarchical list of expandable/collapsible nodes with full keyboard support. Use it to present nested data — file explorers, navigation sidebars, category pickers, or any place users drill into parent/child relationships. Works with either nested or flat source data via the `getKey` / `getChildren` accessors. The root owns selection state (single or multiple, controlled via `v-model` or uncontrolled via `defaultValue`), expanded state (`v-model:expanded`), roving focus and arrow/Home/End navigation, and exposes the computed visible `flatItems` through its default slot for each `TreeItem` to render.
| Prop | Type | Description |
|---|---|---|
items | readonly U[] | Flat or nested item list — children are resolved via getChildren. |
getKey | (item: U) => string | Extract a stable unique string key from an item. |
getChildren? | (item: U) => readonly U[] | undefined | null | Return the children of an item, or undefined if it is a leaf. |
getLabel? | (item: U) => string | Return the text label of an item for type-ahead matching. Defaults to the
rendered textContent of the item element — supply this for non-text nodes
(icons-only) or to override the matched string. |
defaultValue? | string | string[] | Uncontrolled initial selected key(s). |
defaultExpanded? | string[] | Uncontrolled initial expanded keys. |
multiple? | boolean | Allow selecting multiple items. |
disabled? | boolean | Disable the entire tree. |
dir? | 'ltr' | 'rtl' | Writing direction. |
propagateSelect? | boolean | When true, selecting a parent also selects all of its descendants (requires multiple). |
bubbleSelect? | boolean | When true, selecting all children of a parent also selects the parent,
and deselecting any child unselects it — partial coverage surfaces as the
item's indeterminate state (requires multiple). |
selectionBehavior? | 'toggle' | 'replace' | In multiple mode, controls how a click/Enter mutates the selection:
'toggle' (default) flips membership of the clicked item; 'replace'
resets the selection to just that item and arms Shift+Arrow range select. |
modelValue? | string | string[] | undefined | Two-way bound value (v-model). |
expanded? | string[] | Two-way bound value (v-model:expanded). |
| Event | Payload |
|---|---|
update:modelValue | [value: string | string[] | undefined] |
update:expanded | [value: string[]] |
TreeItem
ItemA single node within a `TreeRoot`, rendered once per visible `flatItem`. Handles click-to-select, click-to-toggle for parents, keyboard interaction, and the ARIA treeitem attributes (level, set size/position, selected, expanded). Exposes `isExpanded` / `isSelected` / `isIndeterminate` / `isDisabled` plus imperative `handleSelect` / `handleToggle` callbacks to its slot, so custom sub-nodes (a chevron, a checkbox) can drive state independently. `select` and `toggle` are emitted as cancelable events before the root mutates state — call `event.preventDefault()` to veto.
| Prop | Type | Description |
|---|---|---|
item | FlatItem<U> | Flattened item produced by TreeRoot (from its default slot). |
disabled? | boolean | Disable this specific item. |