Tree View
A keyboard-navigable hierarchy of branches and leaves.
Usage
import {
TreeView,
TreeViewBranch,
TreeViewBranchContent,
TreeViewBranchItem,
TreeViewContent,
TreeViewItem,
TreeViewNode,
TreeViewTree,
createTreeCollection,
} from "@kanzo-tech/ui";const collection = createTreeCollection({ rootNode: tree });
<TreeView collection={collection} defaultExpandedValue={["warm"]}>
<TreeViewTree>{/* recursive nodes */}</TreeViewTree>
</TreeView>;createTreeCollection wraps Ark's with nodeToValue: node => node.id and
nodeToString: node => node.name already filled in, so a tree of { id, name, children }
needs no adapter.
Anatomy
TreeViewBranchIndicator is the chevron that turns as a branch opens — 90 degrees on
data-[state=open], and nothing at all under prefers-reduced-motion. TreeViewBranchItem renders
one for you ahead of the title, so reach for it directly only when the row is arranged differently
and the indicator belongs somewhere other than first.
<TreeView collection>
<TreeViewLabel />
<TreeViewTree>
<TreeViewNode node indexPath> ← recursive
branch: <TreeViewBranch>
<TreeViewBranchItem /> ← indicator + folder icon + text
<TreeViewBranchContent> ← children, plus the indent guide
leaf: <TreeViewContent>
<TreeViewItem />The node renderer is recursive and you write it: a node with children becomes a
TreeViewBranch, everything else a TreeViewContent. indexPath is how Ark locates the
node in the collection, so it must be threaded through each level.
File icons
Leaf icons resolve from the file extension, so a node never carries its own icon. Pass a map
built with createFileIcons; anything unmatched falls back to TreeViewItem's icon.
Keyboard
| Key | Does |
|---|---|
| ↓ / ↑ | Moves focus to the next / previous visible node, stepping into and out of expanded branches. |
| → | Expands the focused branch, or moves to its first child when it is already open; nothing on a leaf. |
| ← | Collapses the focused branch, or moves to the parent when it is already closed. |
| Home / End | Moves focus to the first / last visible node. |
| Enter / Space | Selects the focused node, and toggles a branch open or closed. |
| * | Expands every branch that is a sibling of the focused node. |
| A–Z | Typeahead: moves focus to the next visible node whose label starts with what you have typed. |
| Shift+↓ / ↑ / Home / End | Extends the selection as it moves, under selectionMode="multiple". |
| ⌘+A | Selects every node, under selectionMode="multiple". |
| F2 | Starts renaming the focused node, when the root is given a canRename predicate that returns true for it. The rename input is rendered by the node itself. |
Select-all is bound to the Meta key alone, so Ctrl+A does not reach it on Windows or Linux — while the click path in the same machine treats Ctrl and Meta alike, so pointer and keyboard disagree about the same modifier.
Focus is painted for the keyboard only. Ark marks its roving tab stop data-focus, and with
nothing focused that is the first node — so a row painted on it looks chosen the moment the tree
mounts, before anyone has touched it. The row paints its focus on
:focus-visible instead: arrowing through the tree shows where you are, and a tree nobody has
touched shows nothing but its selection.
What would reverse it: Ark exposing whether its focus is the keyboard's. Then the row reads that attribute rather than the pseudo-class, and nothing a reader sees changes.
Held by packages/ui/src/simples/tree-view.test.tsx, "paints a row's focus for the keyboard
only, not the tab stop Ark marks at rest".
API Reference
TreeView
| Prop | Type | Default |
|---|---|---|
fileIcons | Record<string, ElementType | null> | — |
lazyMount | boolean | true |
unmountOnExit | boolean | true |
TreeViewBranchItem
| Prop | Type | Default |
|---|---|---|
icon | ElementType | null | FolderIcon |
expandedIcon | ElementType | null | FolderOpenIcon |
TreeViewItem
| Prop | Type | Default |
|---|---|---|
icon | ElementType | FileIcon |
Passing null for an icon removes it entirely rather than falling back to the default.
collection, selectionMode, expandedValue and the rest come from Ark's TreeView.Root;
TreeViewCheckbox is available for selectionMode="multiple", and useTreeView re-exports
Ark's context hook.
TreeNodeType is one node — id, name, optional children and its two icons — and
TreeCollection is Ark's collection over them, re-exported so a host builds one without importing
Ark directly. NodeProviderProps is the provider a custom node renderer sits inside.