Filesystem
Render a collapsible file and folder tree with optional custom row rendering and selection state.
Filesystem is a client component that renders a nested list of folders and files. Use it for file browsers, project trees, and other hierarchical lists. Folders with children expand and collapse with a motion/react height animation, and rows can be customised through render callbacks.
- src
- theme.config.ts
- components
- docs
- package.json
Import#
import { Filesystem } from "@reactberry/system/blocks";
Usage#
import { useState } from "react";
import { Filesystem } from "@reactberry/system/blocks";
import { Box } from "@reactberry/system/elements";
const tree = [
{
id: "src",
name: "src",
nodes: [
{ id: "src/index.ts", name: "index.ts" },
{ id: "src/components", name: "components", nodes: [{ id: "src/components/Button.tsx", name: "Button.tsx" }] },
],
},
{ id: "package.json", name: "package.json" },
];
export default function ProjectTree() {
const [selected, setSelected] = useState<string[]>([]);
return (
<Box width="16rem">
<Filesystem
nodes={tree}
initiallyOpenNames={["src"]}
selectedIds={selected}
onSelectNode={(node) => node.id && setSelected([node.id])}
/>
</Box>
);
}
Examples#
Checkboxes#
Use renderLeading to put a checkbox before the default toggle. Passing the checked ids as selectedIds highlights those rows and provides isSelected.
- Photos
- beach.jpg
- city.jpg
- invoice.pdf
Row metadata#
Use renderNode to add content after the default icon and name, such as the number of items in a folder.
- app3
- layout.tsx
- page.tsx
- settings3
- public1
API#
Filesystem#
| Prop | Type | Default | Description |
|---|---|---|---|
nodes* | FilesystemNode[] | — | Top-level nodes. Nothing is rendered when empty. |
initiallyOpenNames | string[] | — | Names (not ids) of folders that start expanded, at any depth. Read on first render only. |
onSelectNode | ((node: FilesystemNode) => void) | — | Called when a row or a folder toggle is clicked. |
renderNode | ((node: FilesystemNode, defaultContent: ReactNode, ctx: FilesystemNodeContext) => ReactNode) | — | Replaces the icon and name. |
renderLeading | ((node: FilesystemNode, ctx: FilesystemLeadingContext) => ReactNode) | — | Override the leading slot (toggle for folders, spacer for leaves) so callers can place a fixed-width control such as a checkbox in the same column as the expand toggle. |
selectedIds | string[] | — | IDs of nodes considered selected. Selected rows get |
No other props are accepted.
FilesystemNode#
| Prop | Type | Default | Description |
|---|---|---|---|
name* | string | — | Row label. Also matched by |
id | string | — | Used by |
nodes | FilesystemNode[] | — | Child nodes. Any array, even empty, makes the node a folder. |
renderLeading context#
| Prop | Type | Default | Description |
|---|---|---|---|
hasChildren | boolean | — |
|
isOpen | boolean | — | Whether the folder is expanded. |
toggle | () => void | — | Expands or collapses the folder. |
defaultLeading | ReactNode | — | The default toggle button, or a spacer for rows without children. |
isSelected | boolean | — | Whether the node's |
Accessibility#
- The tree renders as nested
ulandlielements. There is notreerole,aria-expanded, oraria-selected. - Rows are clickable
divelements without keyboard handling. The folder toggle is a nativebuttonwithout an accessible label.
Notes#
- A node with a
nodesarray is shown with a folder icon, even when empty; only folders with at least one child get a toggle and can expand. - Clicking a row toggles folders with children and calls
onSelectNode. The toggle button stops propagation, toggles, and also callsonSelectNode. - Open state is local to each row;
initiallyOpenNamesis read only on first render. - Nested levels are not indented by default; the internal
depthvalue is tracked but not used for styling. - The root list does not reset
listStyleType, while nested lists set it tonone. - Row names are clamped to one line, with the full name in the row's
titleattribute. - The
FilesystemNodeand related types are not re-exported from the blocks entry point.