Data display
File tree
A file tree, implementing the WAI-ARIA treeview pattern.
Import
import { FileTree } from '@the_viveksingh/vivek-ui'A project tree
The full WAI-ARIA treeview keyboard model: arrows navigate across folder boundaries, Right opens and steps in, Left collapses or moves to the parent, * expands the level, and typing jumps to a match.
Click into the tree, then use the arrow keys. Right opens a folder and steps in, Left collapses or moves out to the parent, and typing a letter jumps to a match.
- src
- components
- hooks
- index.ts
- docs
- package.json
- pnpm-lock.yaml
Selected: nothing yet
const tree = [
{
id: 'src',
label: 'src',
// The presence of a children array is what makes a node a folder.
children: [
{ id: 'index', label: 'index.ts' },
{ id: 'components', label: 'components', children: [...] },
],
},
{ id: 'pkg', label: 'package.json' },
{ id: 'lock', label: 'pnpm-lock.yaml', disabled: true },
]
<FileTree
nodes={tree}
label="Project files"
defaultExpandedIds={['src']}
onSelect={(node) => open(node.id)}
/>Controlled expansion
Drive the open folders yourself to persist them, or to open to a path.
- src
- components
- button.tsx
- button.css
- card.tsx
- hooks
- index.ts
- docs
- package.json
- pnpm-lock.yaml
<FileTree
nodes={tree}
label="Project files"
expandedIds={open}
onExpandedChange={setOpen}
/>Props
Generated from the package's own type declarations, so this table cannot drift from the code.
| Prop | Type | Default | Description |
|---|---|---|---|
nodes required | readonly TreeNode[] | — | — |
label required | string | — | Required. A tree with no accessible name is unnavigable. |
selectedId | string | null | — | — |
defaultSelectedId | string | null | — | — |
onSelect | (node: TreeNode) => void | — | — |
expandedIds | readonly string[] | — | — |
defaultExpandedIds | readonly string[] | — | — |
onExpandedChange | (ids: string[]) => void | — | — |
guides | boolean | — | Show the connecting guide lines. Default `true`. |
className | string | — | — |
Rendering
FileTree declares 'use client' because it needs state, effects or event handlers. Importing it into a Server Component creates a client boundary at this component — everything above it stays on the server.