# Tree A hierarchical list that opens with the arrow keys, selects one node or many, and loads children on demand. ```ehtml Example import { Tree, TreeNode, visibleNodes } from "@elements/ui/tree"; const files: TreeNode[] = [ { id: "src", label: "src", icon: "folder", children: [ { id: "app", label: "app.ts", icon: "file" }, ] }, { id: "readme", label: "README.md", icon: "file" }, ]; ``` ## Parts | Part | What it is | |---|---| | `Tree` | The role="tree" list. Renders every level from items. | | `.tree-item` | A node: li[role=treeitem] holding its row and, when open, its group. | | `.tree-row` | The visible row: toggle, icon, label. Indented by --tree-level. | | `.tree-group` | The role="group" list of an open node's children. | | `visibleNodes(items, expanded, filter?, state?)` | The shown nodes in order, each with its level, set position, index path and parent: the model a virtual tree renders a slice of, for a count or a search. | ## Attributes | Attribute | Type | Default | Description | |---|---|---|---| | `items` | `TreeNode[]` | (required) | The nodes: { id, label, children?, hasChildren?, disabled?, icon?, href? }. A node with href is a link. | | `selected` | `string[]` (two-way) | `[]` | Ids of the selected nodes. | | `expanded` | `string[]` (two-way) | `[]` | Ids of the open nodes. | | `selection` | `"single" \| "multiple" \| "none"` | `"single"` | How many nodes can be selected. | | `selectionFollowsFocus` | `boolean` | `false` | In single mode, moving focus selects the node. | | `expandOnClick` | `boolean` | `true` | A click on a parent's row also opens or closes it. The chevron always does. | | `label` | `string` | `""` | aria-label of the tree. | | `checkboxes` | `boolean` | `false` | Checkbox tree: a box per node, aria-checked, parents mixed when some leaves are checked. | | `checked` | `string[]` | `[]` | Checked leaf ids. Two-way. | | `filter` | `string` | `""` | Shows the nodes whose label contains it and the parents that lead to them, opened. | | `typeahead` | `boolean` | `true` | Letters move focus to the next node by label. | | `indentGuides` | `boolean` | `false` | Draws a rule down each open group, under its parent's chevron. | | `canRename` | `(node: TreeNode) => boolean` | `() => false` | F2 renames a node it allows. | | `renameLabel` | `string` | `"Name"` | aria-label of the rename input. | | `renaming` | `string` (two-way) | `""` | The node being renamed, or empty. Write a node id to start a rename (a Rename button), empty to cancel; F2, Enter and Escape write it back. | | `focused` | `string` (two-way) | `""` | The node that holds the tab stop. Focus writes it; write a node id to move the tab stop there, and focus too while the tree has it. | | `orientation` | `"vertical" \| "horizontal"` | `"vertical"` | horizontal: aria-orientation=horizontal, top-level nodes side by side; Right and Left move between nodes, Down opens, Up closes. | | `onFocusChange` | `(id: string) => void` | `() => {}` | A node took focus. Not called for the caller's writes. | | `onRename` | `(node: TreeNode, label: string) => boolean \| void` | `() => {}` | A rename was saved; update items with the new label. Return false to refuse it: Enter keeps the input open, leaving it discards. | | `onCheckedChange` | `(ids: string[]) => void` | `() => {}` | Called when the user checks or clears nodes. | | `onLoadChildrenComplete` | `(node: TreeNode, children: TreeNode[]) => void` | `() => {}` | Called when loadChildren resolves. | | `loadChildren` | `(node: TreeNode) => TreeNode[] \| Promise` | `() => []` | Loads the children of a node with hasChildren the first time it opens, by the user or through expanded. | | `onSelectedChange` | `(ids: string[]) => void` | `() => {}` | Called when the user changes the selection. | | `onExpandedChange` | `(ids: string[]) => void` | `() => {}` | Called when the user opens or closes a node. | | `onAction` | `(node: TreeNode) => void` | `() => {}` | Called on Enter: open the file, follow the link. | | `onLoadChildrenError` | `(node: TreeNode, error: unknown) => void` | `() => {}` | Called when loadChildren fails. The node closes and the next open tries again. | | `ids` | `{ root?: string; node?: (node: TreeNode) => string }` | `{}` | The tree's id and each node's, for a label or a link elsewhere on the page. | | `virtual` | `boolean` | `false` | Renders only the rows in and near the view, so ten thousand nodes render, scroll and take keys as fast as ten. The tree scrolls itself: give it a height in CSS. | | `estimateSize` | `number` | `32` | virtual: a row's height in px until rows are measured. | | `overscan` | `number` | `8` | virtual: rows rendered past each edge of the view. | | `activeDescendant` | `boolean` | `false` | Focus stays on the tree and aria-activedescendant names the node, APG's alternative to moving focus. The keys are the same. | | `class` | `string` | `""` | Extra classes on the tree. | ## Keyboard | Keys | Action | |---|---| | `ArrowDown / ArrowUp` | Next or previous visible node. | | `ArrowRight` | Opens a closed parent; on an open parent, moves to its first child. | | `ArrowLeft` | Closes an open parent; on a child, moves to its parent. | | `Home / End` | First or last visible node. | | `Enter` | Opens or closes a parent; selects a leaf (single); calls onAction. | | `Space` | Selects (single) or toggles (multiple) the focused node. | | `Shift + Space` | Selects from the last selected node to this one (multiple). | | `Shift + ArrowDown / ArrowUp` | Moves and toggles the node reached (multiple). | | `Ctrl + Shift + Home / End` | Selects from here to the first or last node (multiple). | | `Ctrl + A` | Selects every visible node; again to unselect (multiple). | | `*` | Opens every sibling of the focused node. | | `F2` | Renames the focused node (canRename); Enter saves, Escape cancels. | | `Ctrl + ArrowDown / ArrowUp` | Moves without selecting; Ctrl + Space toggles the focused node (multiple). | | `a-z` | Focuses the next node whose label starts with the typed text. | ## Data attributes | Attribute | Values | On | Description | |---|---|---|---| | `data-state` | `"open" \| "closed"` | tree-item (parents) | | | `data-selected` | present when selected | tree-item | | | `data-disabled` | present when disabled | tree-item | | | `data-loading` | present while children load | tree-item | | | `data-checked / data-indeterminate` | checkbox tree: all or some leaves checked | tree-item | | | `data-renaming` | present while renaming | tree-item | | | `data-depth, data-value, data-path` | the level, the id, the index path ("0/2") | tree-item | | | `data-focus` | present on the focused node | tree-item | | | `data-scope, data-part` | tree-view; tree, branch, item, branch-control, branch-indicator, branch-text, item-text, branch-content, node-checkbox | every part | | | `data-branch` | the branch's id | tree-group | | | `--tree-level` | 1, 2, ... | tree-row | Depth, for indentation | | `data-index, --tree-start` | virtual: the row's place among the shown nodes, and its offset in px | tree-item | | | `--tree-total` | virtual: the height of every shown row, in px | tree | | ## Accessibility - Follows the WAI-ARIA tree view pattern: role="tree" (aria-multiselectable in multiple mode), role="treeitem" nodes, role="group" children. - Parents carry aria-expanded and leaves do not; selectable nodes carry aria-selected true or false. - Every node has aria-level, aria-setsize and aria-posinset, since closed branches are not in the page. - One tab stop: entering the tree focuses the selected node, or the first. Disabled nodes take focus but cannot be chosen. - A node loading its children is aria-busy. - virtual: the rendered treeitems are flat children of the tree, and aria-level, aria-setsize and aria-posinset give each one its place in the whole tree. The focused node stays rendered while the view scrolls, so focus and the tab stop never fall out. ## See also - [Accordion](accordion): A stack of headings that each show and hide a panel, one or several at a time. - [Collapsible](collapsible): A trigger that shows and hides a region, with its height animated. - [Tabs](tabs): Layered panels, one shown at a time, chosen from a list of tabs. - [Breadcrumb](breadcrumb): The path to the current page as a trail of links, composed from parts or built from a list. - [Pagination](pagination): Page numbers with previous and next, from a page count or composed from parts.