Tree
The STD tree kit (src/components/ds/tree/) — the workflow-primitive family for hierarchical navigation and file/folder browsing. Both are thin, presentational compositions over the Surface base primitive and the @phauna/ds WAI-ARIA Tree. Everything takes plain props + callbacks — no server actions, no Prisma rows.
- composition
- TreeView wraps @phauna/ds/grid's <Tree> (re-exported, not forked) and adds default accessors + an optional recessed Surface frame. FileBrowser = a framed TreeView pane + a Surface detail/list pane + a DS <Breadcrumbs> path trail. No tree behaviour is re-implemented.
- a11y
- role=tree → role=treeitem rows carrying aria-level / aria-expanded / aria-selected; roving tabindex (exactly one focusable node). Arrow Up/Down move, Arrow Right/Left open/close or hop parent↔child, Home/End jump, Enter/Space select. Selection reads via aria-selected + an accent rail (never colour alone); transitions respect reduced-motion.
- presentational / controlled
- Selection lives in selectedId and flows out via onSelect; expansion is the DS Tree's own uncontrolled state (seed with defaultExpanded). FileBrowser is controlled-or-uncontrolled (selectedId vs defaultSelectedId). No fetch, no router, no server actions.
- tokens
- All visuals come from the @phauna/ds .tree* catalog + the Surface token variants (--color-surface*, --color-accent*, --color-rule, --radius-*, --dur-*, --ease-brand). Flip the theme to confirm a full re-skin.
TreeView
A thin wrapper over the @phauna/ds WAI-ARIA Tree. Pass a `nodes` array (id / label / children / optional icon + meta) and it just works — default accessors read node.id / node.children / node.label, override any to project a custom shape. `framed` nests the tree in a recessed Surface well with its own scroll viewport; selection is controlled. Click a row or use the keyboard (arrows / Home / End / Enter).
framed (recessed Surface well)
selectedId: teams-march
unframed (bare role=tree)
- nodes / getId / getChildren / renderLabel
- nodes: TreeNode[] (id, label, children?, icon?, meta?). The three accessors default to node.id / node.children / node.label; override to drive a custom node shape without reshaping your data.
- selectedId / onSelect
- Controlled single selection — selectedId highlights a row (aria-selected + accent rail); onSelect(node) fires on click + Enter/Space. Expansion is uncontrolled.
- defaultExpanded
- Ids expanded on first mount (the DS Tree manages expansion thereafter). Branch ids only; leaves are ignored.
- framed / maxHeight
- framed nests the tree in a recessed Surface (inset) well; maxHeight (px number or CSS length, default 20rem) bounds that well's scroll viewport.
FileBrowser
A two-pane file/folder browser: a framed TreeView on the left, a Surface detail/list pane on the right. Selecting a folder shows a DS Breadcrumbs path trail plus a clickable list of its immediate children (drill down without touching the tree); selecting a file shows its metadata + description. Folder/file icons are injected when a node doesn't supply one.
docs
- Type
- Folder
- Items
- 2
- Modified
- Apr 3, 2026
Contents
last picked: —
- nodes
- FileBrowserNode[] = TreeNode + kind ('folder' | 'file', inferred from children when omitted), size, modified, description. The right pane renders from whichever node is selected.
- selectedId / defaultSelectedId / onSelect
- Controlled (selectedId) or uncontrolled (defaultSelectedId seeds internal state). onSelect(node) fires for both tree rows and detail-list rows with the resolved node.
- detail pane
- folder → DS <Breadcrumbs> trail + a clickable list of immediate children (each picks that child); file → trail + a Type/Size/Modified definition list + description. Empty selection shows emptyHint.
- treeLabel / detailActions / treeMaxHeight
- treeLabel names the tree landmark; detailActions slots nodes into the detail header's top-right; treeMaxHeight bounds the tree pane's scroll viewport (default 24rem).