Tree

2 parts

A 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

Loading demo…

Anatomy

Import the parts and compose them. Each part forwards attributes to its underlying element.

vue
import {
  TreeRoot,
  TreeItem,
} from '@robonen/primitives/navigation/tree';

<TreeRoot>
  <TreeItem />
</TreeRoot>

API Reference

TreeRoot

Root

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

PropTypeDescription
itemsreadonly U[]Flat or nested item list — children are resolved via getChildren.
getKey(item: U) => stringExtract a stable unique string key from an item.
getChildren?(item: U) => readonly U[] | undefined | nullReturn the children of an item, or undefined if it is a leaf.
getLabel?(item: U) => stringReturn 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?booleanAllow selecting multiple items.
disabled?booleanDisable the entire tree.
dir?'ltr' | 'rtl'Writing direction.
propagateSelect?booleanWhen true, selecting a parent also selects all of its descendants (requires multiple).
bubbleSelect?booleanWhen 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[] | undefinedTwo-way bound value (v-model).
expanded?string[]Two-way bound value (v-model:expanded).
Emits
EventPayload
update:modelValue[value: string | string[] | undefined]
update:expanded[value: string[]]

TreeItem

Item

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

PropTypeDescription
itemFlatItem<U>Flattened item produced by TreeRoot (from its default slot).
disabled?booleanDisable this specific item.