Tree
Tree renders a hierarchical data structure with expand/collapse, keyboard navigation, and type-ahead search. Common use cases include file explorers, category trees, and nested menu structures. Selected items are indicated with a semibold label and accent background. Focused items show a ring indicator.
Interactive example#
Tree · Live example
Expand folders, choose a file, or collapse the whole tree.
The code uses shared demo presentation helpers. Their complete source and styling are included in the LLM build context.
Import#
TSX
import { Tree } from '@clidey/ux';
import type { TreeDataItem } from '@clidey/ux';
Basic tree#
TSX
const treeData: TreeDataItem[] = [
{
id: '1',
name: 'src',
children: [
{
id: '1-1',
name: 'components',
children: [
{ id: '1-1-1', name: 'Button.tsx' },
{ id: '1-1-2', name: 'Card.tsx' },
{ id: '1-1-3', name: 'Input.tsx' },
],
},
{
id: '1-2',
name: 'lib',
children: [
{ id: '1-2-1', name: 'utils.ts' },
{ id: '1-2-2', name: 'api.ts' },
],
},
],
},
{ id: '2', name: 'package.json' },
{ id: '3', name: 'tsconfig.json' },
];
<Tree data={treeData} />
With selection#
TSX
function FileExplorer() {
const [selected, setSelected] = useState<TreeDataItem | undefined>();
return (
<div className="flex gap-4">
<div className="w-56 border rounded-lg p-2">
<Tree
data={treeData}
onSelectChange={setSelected}
/>
</div>
<div className="flex-1 p-4">
{selected ? (
<p>Selected: <code>{selected.name}</code></p>
) : (
<p className="text-muted-foreground">Select a file</p>
)}
</div>
</div>
);
}
With default selection#
TSX
<Tree
data={treeData}
initialSelectedItemId="1-1-1"
onSelectChange={(item) => console.log(item)}
/>
Expand all by default#
TSX
<Tree data={treeData} expandAll />
Custom icons#
Override the default folder and item icons:
TSX
import { IconFolder as Folder, IconFileText as FileText } from '@clidey/ux';
<Tree
data={treeData}
folderIcon={Folder}
itemIcon={FileText}
/>
With per-item icons#
Set an icon on individual TreeDataItem entries:
TSX
import { IconFileCode as FileJson, IconFileCode as FileCode, IconFolder as FolderOpen } from '@clidey/ux';
const treeData: TreeDataItem[] = [
{
id: '1',
name: 'src',
icon: FolderOpen,
children: [
{ id: '1-1', name: 'index.ts', icon: FileCode },
{ id: '1-2', name: 'config.json', icon: FileJson },
],
},
];
Keyboard navigation#
Click inside the tree to focus it, then use keyboard shortcuts:
| Key | Action |
|---|---|
↑ / ↓ | Move focus between visible nodes |
→ | Expand collapsed folder, or move to first child |
← | Collapse expanded folder, or move to parent |
Enter / Space | Select the focused node |
Home / End | Jump to first / last visible node |
| Type a letter | Jump to next node whose name starts with that character |
Type-ahead resets after 500ms of inactivity, allowing multi-character search (e.g., type "re" to jump to "Reports").
Controlled expand/collapse#
Control which nodes are expanded externally (useful for search filtering):
TSX
function SearchableTree() {
const [expandedIds, setExpandedIds] = useState<string[]>([]);
return (
<Tree
data={treeData}
expandedIds={expandedIds}
onExpandChange={setExpandedIds}
/>
);
}
Props#
Tree
| Prop | Type | Default | Description |
|---|---|---|---|
data | TreeDataItem[] | TreeDataItem | — | The tree data to render. |
initialSelectedItemId | string | — | ID of the item selected on initial render. |
onSelectChange | (item: TreeDataItem | undefined) => void | — | Called when the selected item changes. |
expandAll | boolean | false | Expands all nodes on initial render. |
expandedIds | string[] | — | Controlled expanded node IDs. |
onExpandChange | (ids: string[]) => void | — | Called when expand state changes. |
folderIcon | LucideIcon | — | Custom icon for folder nodes. |
itemIcon | LucideIcon | — | Custom icon for leaf nodes. |
className | string | — | Additional CSS classes. |
TreeDataItem type
TSX
type TreeDataItem = {
id: string;
name: string;
icon?: LucideIcon;
children?: TreeDataItem[];
};
Note
Keyboard navigation follows the WAI-ARIA treeview pattern. Focus remains on the tree container; individual nodes are highlighted via aria-activedescendant.
Was this page helpful?
