Tree
Hierarchical data grid for visualizing nested folders, file explorers, and deep parent-child navigation.
Tree
A Tree displays hierarchical data structured into expandable and collapsible branches. It is standard for file directory browsers, organization charts, categorized product taxonomies, and nested JSON/code inspectors.
Built upon React Aria Components’ Tree pattern, Hashti unites architectural TreeView elegance with RAC’s accessible treegrid implementation. Features include optional architectural guideline rules (showGuideLines), recursive chevron indicators, multi-item selection with checkboxes, and keyboard branch navigation.
Import
import { Tree } from "@hashti/react";
// Or named subcomponents:
// Tree.Root, Tree.Item, Tree.Indicator, Tree.Content, Tree.Checkbox
Anatomy
<Tree aria-label="Project filesystem">
<Tree.Item textValue="src">
<Tree.Indicator />
<Tree.Content>src</Tree.Content>
<Tree.Item textValue="components">
<Tree.Indicator />
<Tree.Content>components</Tree.Content>
</Tree.Item>
</Tree.Item>
</Tree>
Examples
File Directory Explorer
Construct a multi-level file hierarchy with custom folder and document icons:
import { Tree, Icon } from "@hashti/react";
const fileHierarchy = [
{
id: "src",
name: "src",
type: "folder",
children: [
{
id: "components",
name: "components",
type: "folder",
children: [
{ id: "button.tsx", name: "button.tsx", type: "file" },
{ id: "toolbar.tsx", name: "toolbar.tsx", type: "file" },
{ id: "tree.tsx", name: "tree.tsx", type: "file" },
],
},
{ id: "index.ts", name: "index.ts", type: "file" },
{ id: "styles.css", name: "styles.css", type: "file" },
],
},
{ id: "package.json", name: "package.json", type: "file" },
{ id: "README.md", name: "README.md", type: "file" },
];
export function FileTreeExplorer() {
return (
<div className="max-w-md p-4 border border-[var(--divider)] rounded-lg">
<h3 className="text-sm font-semibold mb-3">Project Directory</h3>
<Tree aria-label="Filesystem Tree" items={fileHierarchy} showGuideLines size="md">
{function renderItem(item: any) {
const isFolder = item.type === "folder";
return (
<Tree.Item key={item.id} textValue={item.name}>
<div className="flex items-center gap-2 py-1">
{isFolder && <Tree.Indicator />}
<Icon
name={isFolder ? "menu" : "edit"}
size={16}
className="text-[var(--text-muted)]"
/>
<Tree.Content>{item.name}</Tree.Content>
</div>
{item.children && item.children.map(renderItem)}
</Tree.Item>
);
}}
</Tree>
</div>
);
}
Multi-Item Selection with Checkboxes
Enable batch selection across parent and child nodes by setting selectionMode="multiple" and including <Tree.Checkbox />:
import { useState } from "react";
import { Tree } from "@hashti/react";
import type { Selection } from "react-aria-components";
export function SelectableTreeExample() {
const [selected, setSelected] = useState<Selection>(new Set(["button.tsx"]));
return (
<div className="max-w-md space-y-3">
<Tree
aria-label="Export file selection"
selectionMode="multiple"
selectedKeys={selected}
onSelectionChange={setSelected}
>
<Tree.Item id="frontend" textValue="Frontend">
<div className="flex items-center gap-2 py-1">
<Tree.Indicator />
<Tree.Checkbox />
<Tree.Content>Frontend Applications</Tree.Content>
</div>
<Tree.Item id="docs" textValue="Documentation">
<div className="flex items-center gap-2 py-1">
<Tree.Indicator />
<Tree.Checkbox />
<Tree.Content>Astro Docs</Tree.Content>
</div>
</Tree.Item>
<Tree.Item id="storybook" textValue="Storybook">
<div className="flex items-center gap-2 py-1">
<Tree.Indicator />
<Tree.Checkbox />
<Tree.Content>Storybook Workshop</Tree.Content>
</div>
</Tree.Item>
</Tree.Item>
</Tree>
</div>
);
}
Guide Lines
The showGuideLines prop renders subtle vertical alignment lines connecting nested child rows to their ancestor folders. This aids visual scanning in deeply nested hierarchies (4+ levels deep).
<Tree showGuideLines={true} aria-label="Deeply nested tree">
{/* Nested items */}
</Tree>
Props Reference
Tree (Tree.Root)
| Prop | Type | Default | Description |
|---|---|---|---|
selectionMode | 'none' | 'single' | 'multiple' | 'none' | Row selection mode. |
selectedKeys | 'all' | Iterable<Key> | — | Currently selected node keys. |
onSelectionChange | (keys: Selection) => void | — | Callback fired on selection change. |
expandedKeys | 'all' | Iterable<Key> | — | Keys of nodes currently expanded. |
defaultExpandedKeys | 'all' | Iterable<Key> | — | Keys expanded initially. |
onExpandedChange | (keys: Set<Key>) => void | — | Callback fired when branches expand or collapse. |
showGuideLines | boolean | true | Whether to display vertical dashed branch guideline rules. |
size | 'sm' | 'md' | 'md' | Row height and indentation density. |
aria-label | string | — | Accessible tree description. |
Tree.Item (TreeItem)
| Prop | Type | Default | Description |
|---|---|---|---|
id | Key | — | Unique key identifying this tree node. |
textValue | string | — | Plain text string used for keyboard typeahead navigation. |
isDisabled | boolean | false | Whether this node cannot be expanded or selected. |
Tree.Indicator (TreeIndicator)
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | <Icon name="chevronRight" /> | Expand/collapse arrow. Rotates 90° when expanded. |
Tree.Checkbox (TreeCheckbox)
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Optional custom checkbox label. |
Keyboard Interactions
Hashti Tree adheres to the WAI-ARIA Treegrid Pattern:
| Key | Action |
|---|---|
| → | When on a collapsed node, expands the branch. When on an expanded node, moves focus to the first child. |
| ← | When on an expanded node, collapses the branch. When on a child node, moves focus to the parent node. |
| ↓ / ↑ | Moves focus vertically between visible nodes without expanding closed branches. |
| Enter / Space | Toggles node selection or activates the primary action. |
| * (Asterisk) | Expands the focused node and all its siblings at the same depth. |
| Home / End | Moves focus directly to the first or last visible node. |
Hashti Token Bindings
| Token | CSS Variable | Applied Element |
|---|---|---|
| Guideline Stroke | --divider | 1px vertical branch indentation guide |
| Selected Surface | --selected (#e7edff) | Highlight background for selected nodes |
| Focus Ring | --focus | 2px focus border on active node |
| Hover State | --surface-hover | Subtle row hover feedback |
| Text Main | --text | Primary node label |
| Text Muted | --text-muted | File icons and metadata |
Keyboard Interactions
| Key | Action |
|---|---|
| ↓ / ↑ | Navigates between visible tree nodes. |
| → | Expands collapsed branch node, or moves into first child. |
| ← | Collapses expanded branch node, or moves back to parent. |
| Home / End | Jumps to the first or last visible tree node. |
| Space | Toggles node selection. |
WAI-ARIA & Data Attributes
| Attribute | Target | Description |
|---|---|---|
[data-hovered] | Tree Node | Active on pointer hover. |
[data-selected] | Tree Node | Set when tree item is selected. |
[data-expanded] | Tree Branch | Present on expanded branch nodes. |
[data-focused] | Tree Node | Set when tree item holds focus. |