Skip to content

Tree

Tree

Basic Tree

src
index.ts

Controlled Expansion

Expanded: src, components

src
components
Button.tsx
Input.tsx
Modal.tsx
index.ts

With Actions

src
index.ts

Built from Flat Data

Using buildTree() utility

Animals
Mammals
Dog
Cat
Birds
Eagle
Plants
Trees

Empty State

No files found
import { Tree, type TreeNode } from "@f0rbit/ui";
const nodes: TreeNode[] = [
{
id: "src",
label: "src",
children: [
{ id: "index", label: "index.ts" },
{ id: "utils", label: "utils.ts" },
],
},
];
<Tree nodes={nodes} />
PropTypeDefaultDescription
nodesTreeNode[] | TreeNodeTree node(s) to render
renderNode(node: TreeNode, depth: number) => JSX.ElementCustom node label rendering
renderActions(node: TreeNode, depth: number) => JSX.ElementRender action buttons for each node
showGuidesbooleantrueShow tree guide lines
defaultExpandedboolean | string[]trueInitial expansion state (uncontrolled)
expandedstring[]Controlled expansion state (node IDs)
onExpandedChange(expanded: string[]) => voidCallback when expansion changes
emptyMessagestring"No items"Message when tree is empty

Use the buildTree utility to convert flat data with parentId references:

import { Tree, buildTree, type FlatTreeItem } from "@f0rbit/ui";
const items: FlatTreeItem[] = [
{ id: "1", label: "Root", parentId: null },
{ id: "2", label: "Child", parentId: "1" },
{ id: "3", label: "Grandchild", parentId: "2" },
];
<Tree nodes={buildTree(items)} />

Control initial expansion state with defaultExpanded:

// All collapsed
<Tree nodes={nodes} defaultExpanded={false} />
// All expanded
<Tree nodes={nodes} defaultExpanded />
// Specific nodes expanded
<Tree nodes={nodes} defaultExpanded={["src", "components"]} />

For controlled expansion, use expanded and onExpandedChange:

const [expanded, setExpanded] = createSignal<string[]>(["src"]);
<Tree
nodes={nodes}
expanded={expanded()}
onExpandedChange={setExpanded}
/>

Customize how nodes are rendered with renderNode:

<Tree
nodes={nodes}
renderNode={(node, depth) => (
<span style={{ color: depth === 0 ? "blue" : "inherit" }}>
{node.label}
</span>
)}
/>

Add action buttons to nodes with renderActions:

<Tree
nodes={nodes}
renderActions={(node) => (
<Button size="sm" variant="ghost" onClick={() => handleSelect(node)}>
Select
</Button>
)}
/>

Tree guides are shown by default. Disable with showGuides={false}:

<Tree nodes={nodes} showGuides={false} />

Customize the empty state message:

<Tree nodes={[]} emptyMessage="No files found" />
<Tree
nodes={fileSystem}
defaultExpanded={["src"]}
renderNode={(node) => (
<span>
{node.children?.length ? "folder" : "file"} {node.label}
</span>
)}
/>
const orgChart = buildTree(employees);
<Tree
nodes={orgChart}
defaultExpanded
renderActions={(node) => (
<Button size="sm" onClick={() => viewEmployee(node.data)}>
View
</Button>
)}
/>
<Tree
nodes={categories}
expanded={expanded()}
onExpandedChange={setExpanded}
renderNode={(node) => (
<a href={`/category/${node.id}`}>{node.label}</a>
)}
/>