Tree
A hierarchical list for browsing nested data such as file systems, with expandable folders, optional guide lines, lazy-loaded children, and single or multi selection.
Install
Pull Tree from the barrel for everyday use, or the granular path when you want a tighter bundle.
import { Tree } from "@brika/clay";import { Tree } from "@brika/clay/components/tree";A minimal example
Drop this into a page. Native HTML attributes pass through to the underlying primitive.
'use client';
import { Tree, TreeItem } from '@brika/clay/components/tree';
/** Folders expand on click with single-select, vertical guide lines connect nested items. */
export default function TreeDefaultDemo() {
return (
<Tree
className="w-full max-w-xs"
showLines
defaultExpandedIds={['src', 'src/components']}
defaultSelectedIds={['src/components/button.tsx']}
>
<TreeItem nodeId="src" label="src">
<TreeItem nodeId="src/components" label="components">
<TreeItem nodeId="src/components/button.tsx" label="button.tsx" />
<TreeItem nodeId="src/components/card.tsx" label="card.tsx" />
</TreeItem>
<TreeItem nodeId="src/index.ts" label="index.ts" />
<TreeItem nodeId="src/styles.css" label="styles.css" />
</TreeItem>
<TreeItem nodeId="public" label="public">
<TreeItem nodeId="public/favicon.ico" label="favicon.ico" />
</TreeItem>
<TreeItem nodeId="package.json" label="package.json" />
<TreeItem nodeId="README.md" label="README.md" />
</Tree>
);
}Tree, every way
Lazy loading
Folders fetch their children on first expand (Suspense + use) with a spinner while in flight; a failed load (the restricted folder) renders <TreeError/> instead.
Multi-select
Cmd/Ctrl-click (or press Enter) to select several nodes; selection is controlled.
Without Icons
Hide the folder/file glyphs with `showIcons={false}` for a denser list.
Accessibility
- Root carries
role="tree"; each node is arole="treeitem"witharia-expandedon folders andaria-selectedon selectable nodes. - Nested groups use
role="group"so assistive tech announces nesting depth. - Arrow keys move between visible nodes; Right/Left expand and collapse folders (or step in and out); Home/End jump to the first and last node.
- Enter or Space selects a node; hold Cmd/Ctrl to extend selection when
multiSelectis enabled. - A node fetching its children (
loading) carriesaria-busywhile the request is in flight.
Theme tokens
Every CSS variable Tree reads, with its default and the
dotted path you'd write in a ThemeConfig JSON
to override it. Set any of these in your theme to retune Tree
without touching component code.
Tree tokens
14 tokens--tree-guidecolorvar(--border)components.tree.guideColor of the vertical guide lines connecting nested items (shown when `showLines`).
--tree-iconcolorvar(--muted-foreground)components.tree.iconColor of the chevron and file glyphs.
--tree-folder-iconcolorvar(--primary)components.tree.folderIconColor of the folder and folder-open glyphs. Defaults to the brand primary so folder icons pick up the theme accent color automatically.
--tree-labelcolorvar(--foreground)components.tree.labelText color of a resting tree row.
--tree-item-hovercolorvar(--accent)components.tree.itemHoverRow background on hover.
--tree-selectedcolorcolor-mix(in oklch, var(--primary) 12%, transparent)components.tree.selectedRow background when the node is selected. Defaults to a light tint of the brand primary.
--tree-selected-labelcolorvar(--primary)components.tree.selectedLabelRow text color when the node is selected. Defaults to the brand primary so text and file icon read in the theme accent color.
--tree-selected-accentcolorvar(--primary)components.tree.selectedAccentColor of the vertical accent bar on the leading edge of a selected row. Defaults to the brand primary so it picks up theme coral, navy, etc. automatically.
--tree-indentsize1.25remcomponents.tree.indentHorizontal indentation added per nesting level.
--tree-padding-xsizecalc(var(--spacing) * 2)components.tree.paddingXInline padding inside the tree.
--tree-padding-ysizecalc(var(--spacing) * 1.5)components.tree.paddingYBlock padding inside the tree.
--tree-gapsizecalc(var(--spacing) * 2)components.tree.gapGap between adjacent children inside the tree.
--tree-durationdurationvar(--motion-standard-duration)components.tree.durationTransition duration for tree state changes.
--tree-easingeasingvar(--motion-standard-easing)components.tree.easingTransition easing for tree state changes.
Override in a theme
Authoring a theme is plain JSON. Drop overrides under
components.tree, the names
are camelCase versions of the variable suffix.
{
"id": "my-theme",
"name": "My Theme",
"description": "...",
"accentSwatches": ["#000"],
"components": {
"tree": {
"paddingX": "calc(var(--spacing) * 2)"
}
}
}
Then apply with applyTheme(myTheme)
(see the theming guide),
scope it to a subtree with themeToCssVars(myTheme, mode),
or consume any token directly in your own JSX with the matching Tailwind utility
(e.g. bg-tree-…) — see the
chips on each token row.
API reference
Props specific to Tree. Native HTML attributes pass through to the underlying primitive, see the component source on GitHub for the full type signature.
<Tree />
10 props- readonly string[]Folder ids open on first render (uncontrolled).
- readonly string[]Selected node ids on first render (uncontrolled).
- readonly string[]Open folder ids (controlled). Pair with
onExpandedChange. - multiSelectdefault
falsebooleanAllow more than one node to be selected (Cmd/Ctrl-click extends). - (id: string) => voidFires once with a node's id the first time it expands (the open transition). Use it to lazy-load that node's children from an API: mark the node
lazyso it shows a chevron before its children exist, and toggle itsloadingprop while the request is in flight. - (ids: string[]) => voidFires with the next set of open folder ids whenever a folder toggles.
- (ids: string[]) => voidFires with the next set of selected node ids whenever selection changes.
- readonly string[]Selected node ids (controlled). Pair with
onSelectedChange. - showIconsdefault
truebooleanRender folder/file glyphs beside each label. Defaults totrue. - showLinesdefault
falsebooleanDraw vertical guide lines connecting nested items. Defaults tofalse.
<DepthContext />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<GuideLines />
1 prop- number
No description.
<TreeContext />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<TreeError />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<TreeItem />
6 props- React.ReactNodeRow label.
- stringStable identifier used for expansion and selection state.
- disableddefault
falsebooleanBlock expansion and selection for this node. - React.ReactNodeOverride the default folder/file glyph.
- lazydefault
falsebooleanTreat this node as an expandable folder even before its children exist, so it shows a chevron and can be opened. Pair with the Tree'sonExpandto fetch children on demand. Defaults tofalse. - loadingdefault
falsebooleanShow a spinner in place of children while they are being fetched. Has an effect only on alazy(or otherwise childless) open node.
<TreeItemGroup />
2 props- boolean
No description.
- boolean
No description.
<TreeLoading />
passthroughNo wrapper-specific props, all attributes pass through to the underlying primitive.
<TreePlaceholder />
2 props- string
No description.
- string
No description.
<TreeRow />
9 props- number
No description.
- boolean
No description.
- React.ReactNode
No description.
- boolean
No description.
- boolean
No description.
- React.ReactNode
No description.
- boolean
No description.
- boolean
No description.
- boolean
No description.