Primitive / Atombeta

Tree

Hierarchical tree view for file structures, navigation, and nested data.

@glinui/uiComponent: tree

Installation$

Package Manager$

pnpm add @glinui/ui @glinui/tokens

Registry$

pnpm dlx @glinui/cli@latest add tree

Usage$

Pass a nodes array of TreeNode objects. Nodes with a children array render as expandable folders; leaf nodes without children render as files. Folders are expanded by default.

button.tsx
input.tsx
card.tsx
index.ts
App.tsx
package.json
tsconfig.json
TSX
1import { Tree } from "@glinui/ui"
2
3const nodes = [
4{
5 label: "src",
6 children: [
7 {
8 label: "components",
9 children: [
10 { label: "button.tsx" },
11 { label: "input.tsx" },
12 { label: "card.tsx" }
13 ]
14 },
15 { label: "index.ts" },
16 { label: "App.tsx" }
17 ]
18},
19{ label: "package.json" },
20{ label: "tsconfig.json" }
21]
22
23export function TreeBasicDemo() {
24return <Tree nodes={nodes} className="max-w-xs" />
25}

Examples$

Glass Variant$

The glass variant applies backdrop-blur and a subtle surface tint, suitable for floating panels and sidebars on blurred backgrounds.

button.tsx
input.tsx
card.tsx
index.ts
App.tsx
package.json
tsconfig.json
TSX
1import { Tree } from "@glinui/ui"
2
3const nodes = [
4{
5 label: "src",
6 children: [
7 { label: "components", children: [{ label: "button.tsx" }, { label: "input.tsx" }] },
8 { label: "index.ts" }
9 ]
10},
11{ label: "package.json" }
12]
13
14export function TreeGlassDemo() {
15return (
16 <div className="bg-gradient-to-br from-neutral-950 to-neutral-900 rounded-xl p-6">
17 <Tree nodes={nodes} variant="glass" className="max-w-xs" />
18 </div>
19)
20}

All Variants$

Four surface variants match the design system — default, glass, outline, and ghost.

Default

index.ts
App.tsx
package.json

Glass

index.ts
App.tsx
package.json

Outline

index.ts
App.tsx
package.json

Ghost

index.ts
App.tsx
package.json
TSX
1import { Tree } from "@glinui/ui"
2
3const nodes = [
4{ label: "src", children: [{ label: "index.ts" }, { label: "App.tsx" }] },
5{ label: "package.json" }
6]
7
8export function TreeVariantsDemo() {
9return (
10 <div className="grid grid-cols-2 gap-4">
11 <div>
12 <p className="mb-2 text-xs font-semibold text-neutral-500 uppercase tracking-widest">Default</p>
13 <Tree nodes={nodes} variant="default" />
14 </div>
15 <div>
16 <p className="mb-2 text-xs font-semibold text-neutral-500 uppercase tracking-widest">Glass</p>
17 <Tree nodes={nodes} variant="glass" />
18 </div>
19 <div>
20 <p className="mb-2 text-xs font-semibold text-neutral-500 uppercase tracking-widest">Outline</p>
21 <Tree nodes={nodes} variant="outline" />
22 </div>
23 <div>
24 <p className="mb-2 text-xs font-semibold text-neutral-500 uppercase tracking-widest">Ghost</p>
25 <Tree nodes={nodes} variant="ghost" />
26 </div>
27 </div>
28)
29}

With Badges$

Add a badge string and optional badgeVariant to any node. Badges appear after the label and support five semantic color tones: default, success, warning, info, and destructive.

index.ts
theme.css
index.ts
index.ts
TSX
1import { Tree } from "@glinui/ui"
2
3const nodes = [
4{
5 label: "packages",
6 children: [
7 { label: "ui", badge: "stable", badgeVariant: "success", children: [{ label: "index.ts" }] },
8 { label: "tokens", badge: "stable", badgeVariant: "success", children: [{ label: "theme.css" }] },
9 { label: "motion", badge: "beta", badgeVariant: "warning", children: [{ label: "index.ts" }] },
10 { label: "registry", badge: "wip", badgeVariant: "info", children: [{ label: "index.ts" }] }
11 ]
12}
13]
14
15export function TreeBadgeDemo() {
16return <Tree nodes={nodes} className="max-w-xs" />
17}

buildFileTree Utility$

buildFileTree converts a flat array of slash-separated file paths into a nested TreeNode[] structure. Pass an optional hrefPrefix to make leaf nodes into links, or getBadge to attach badges based on file path patterns.

button.tsx
input.tsx
cn.ts
utils.ts
index.ts
package.json
TSX
1import { Tree, buildFileTree } from "@glinui/ui"
2
3const paths = [
4"src/components/button.tsx",
5"src/components/input.tsx",
6"src/lib/cn.ts",
7"src/lib/utils.ts",
8"src/index.ts",
9"package.json"
10]
11
12export function TreeBuildFileTreeDemo() {
13const nodes = buildFileTree(paths)
14return <Tree nodes={nodes} className="max-w-xs" />
15}
16
17// With href links and badges:
18export function TreeBuildFileTreeLinkedDemo() {
19const nodes = buildFileTree(paths, {
20 hrefPrefix: "https://github.com/org/repo/blob/main",
21 getBadge: (path) => {
22 if (path.endsWith(".tsx")) return { badge: "tsx", badgeVariant: "info" }
23 if (path.endsWith(".ts")) return { badge: "ts", badgeVariant: "default" }
24 return null
25 }
26})
27return <Tree nodes={nodes} className="max-w-xs" />
28}

Collapsed by Default$

Set defaultExpanded={false} to render all folders in their collapsed state initially.

package.json
tsconfig.json
TSX
1import { Tree } from "@glinui/ui"
2
3const nodes = [
4{
5 label: "src",
6 children: [
7 { label: "components", children: [{ label: "button.tsx" }, { label: "input.tsx" }] },
8 { label: "index.ts" }
9 ]
10},
11{ label: "package.json" }
12]
13
14export function TreeCollapsedDemo() {
15return <Tree nodes={nodes} defaultExpanded={false} className="max-w-xs" />
16}

Accessibility$

  • Folder nodes render as <button> elements, making them keyboard-activatable with Enter and Space.
  • The chevron icon provides a clear visual indicator of expanded/collapsed state.
  • Leaf nodes that have an href render as <a> elements with proper rel="noopener noreferrer" when external is set.
  • Nesting depth is communicated visually through padding-left indentation. For screen-reader depth cues, consider wrapping the component in a <nav> with an aria-label.

Reduced Motion$

The chevron rotation transition (duration-150) is a lightweight CSS transform. It respects prefers-reduced-motion via Tailwind's motion-reduce:transition-none utility if applied to spotlightClassName, and can be suppressed by adding motion-reduce:transition-none to the className prop.

API Reference$

Tree$

PropTypeRequiredDefaultDescription
classNamestringNo-Extra classes for the tree root wrapper.
defaultExpandedbooleanNotrueExpand all folders by default
nodesTreeNode[]Yes-Tree data
variant"default" | "glass" | "outline" | "ghost"No"default"Variant option from treeVariants.

TreeNode$

| Prop | Type | Description | | --- | --- | --- | | label | string | Display text for the node. | | children | TreeNode[] | Nested child nodes; presence makes the node a folder. | | href | string | Optional URL for leaf nodes. | | external | boolean | Opens href in a new tab with rel="noopener noreferrer". | | badge | string | Short badge text shown after the label. | | badgeVariant | "default" \| "success" \| "warning" \| "info" \| "destructive" | Semantic badge tone. | | icon | React.ReactNode | Custom leaf icon override (defaults to FileText). |

buildFileTree$

TS
1function buildFileTree(
2 paths: string[],
3 options?: {
4 hrefPrefix?: string
5 getBadge?: (path: string) => { badge: string; badgeVariant?: TreeNode["badgeVariant"] } | null
6 }
7): TreeNode[]

Converts a flat array of slash-separated paths into a nested TreeNode[]. The hrefPrefix is prepended to each leaf path to form a link URL. getBadge receives the full file path and returns badge metadata or null.

Source$

TSX
1import { Tree, buildFileTree } from "@glinui/ui"
packages/ui/src/components/tree.tsx

Generated API Snapshot

Beta

Auto-extracted from TypeScript source in packages/ui/src/components/tree.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.

Generated: 2026-02-19T17:59:28.468Z · Full index: /docs/api-metadata

Primary Props Type

TreeProps

TreeProps

PropTypeRequiredDefaultDescription
classNamestringNo-Extra classes for the tree root wrapper.
defaultExpandedbooleanNotrueExpand all folders by default
nodesTreeNode[]Yes-Tree data
variant"default" | "glass" | "outline" | "ghost"No"default"Variant option from treeVariants.