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