Corpora UI

Tree

Nested item tree in four shapes: app navigation with collapsible sections, a table of contents, an icon rail, and an editable file explorer. Every row is a Button; navigation flows through onNavigate.

Preview

Use the controls to explore the component's props.

Props

PropTypeDefaultDescription
variant"navigation" | "toc" | "sidebar" | "files"—navigation: app nav — 3-level data promotes the top level to collapsible section names. toc: top-level nodes are routes, deeper rows jump to #{id} after select; parents expand from an overlay chevron. sidebar: single-level icon rail that fills its container; collapsing folds labels to icon tiles. files: compact explorer with rename, drag-and-drop and trailing actions.
itemsITreeNode[]—The tree data — id, label, icon, href (metadata for onNavigate; rows never render anchors, though toc rows below the route level still jump to #{id} or a #hash href), badge, defaultOpen, children.
activeIdstring—id of the current entry, any depth. Marks the row aria-current and expands its collapsed ancestors.
onNavigate(node: ITreeNode) => void—Fires for every selection after the node's own onSelect. Rows are buttons, so this is the routing path — wire your router's navigate here. toc rows below the route level additionally jump to #{id} after it fires.
collapsedbooleanfalsesidebar only — folds rows to their leading icon; the label moves into aria-label and a hover/focus tooltip.
onMove(id, parentId: string | null, index: number) => void—files only — enables drag-and-drop. Reorder items yourself; the moveNode helper is exported.
onRename(id, label: string) => void—files only — enables inline rename (double-click or F2).
renderTrailing(node: ITreeNode) => ReactNode—files only — row actions revealed on hover/focus, e.g. a menu or delete button. Rendered beside the row, not inside it, so the content may be interactive; the row reserves ~36px for it, and a wider slot overlaps the truncated label.
soundbooleantrueExpand/collapse cues. Silent until bindSounds().
treeITreeController—A useTree() controller, in place of items and the handler props. Every behaviour — expand, collapse, select, rename, reorder, fold the rail — becomes callable from outside the component.
treeIdstring—Names this instance in the shared store so useTreeState(id) / useTreeActions(id) can reach it from anywhere under ExegiaProvider. A named tree keeps its state across unmounts (a rail's fold survives a route change) — call removeTreeInstance(id) on teardown. Unnamed trees are dropped on unmount.

Example

import { Tree, useTree, useTreeActions, useTreeState } from "@exegia/corpora-ui"

// Props form — the tree owns its state.
<Tree
  variant="navigation"
  items={items}
  activeId={pathnameId}
  onNavigate={(node) => navigate(node.href!)}
/>

// Controller form — drive it from anywhere.
const tree = useTree({ variant: "files", defaultItems: files })

<Tree tree={tree} />
<Button onClick={tree.collapseAll}>Collapse all</Button>
<Button onClick={() => tree.startRename(tree.activeId!)}>Rename</Button>

// By id — no controller to pass around. Needs <ExegiaProvider> at the root.
<Tree variant="sidebar" treeId="app-nav" items={items} />

// …anywhere else in the app:
const nav = useTreeActions("app-nav")          // writes only, never re-renders
const { collapsed } = useTreeState("app-nav")  // subscribes to the tree
<Button onClick={nav.toggleCollapsed}>{collapsed ? "Expand" : "Fold"} rail</Button>

Last updated on

On this page