Tree
A folder tree with checkboxes, drag & drop, rename, context menu and buttons that change it.
Nodes
A tree shows nodes: { id, label, children }. A node with children is a folder; expanded: true opens it at the start. Optional: icon, badge, description, disabled, and any data of your own.
Options switch features on: checkboxes (with cascadeCheck, folders check their children), showLines, draggable (drag a node onto / between others), editable (F2 or double-click to rename), contextMenu (right-click), filters and search.
Everything can also be changed from outside: the field and buttons above the tree call api.addTreeNode, updateTreeNode, removeTreeNode, selectTreeNode, setTreeSearch, expandAllTree, ...
Try it
Code
Copy Full page.js into app/your-page/page.js of a Next.js app (withrcube-html, react-bootstrap and Bootstrap's CSS installed) — it runs as is. Or copy only the schema and keep your own page.
[
{
"type": "row",
"id": "row-controls",
"children": [
{
"type": "column",
"id": "c-name",
"props": {
"className": "col-12 col-md-4"
},
"children": [
{
"type": "InputField",
"id": "item-name",
"props": {
"name": "itemName",
"label": "Item name",
"placeholder": "Header.js — end with / for a folder"
}
}
]
},
{
"type": "column",
"id": "c-find",
"props": {
"className": "col-12 col-md-4"
},
"children": [
{
"type": "InputField",
"id": "find",
"props": {
"name": "find",
"label": "Find",
"placeholder": "type to filter",
"onChange": "findChanged()"
}
}
]
},
{
"type": "column",
"id": "c-view",
"props": {
"className": "col-12 col-md-4"
},
"children": [
{
"type": "SelectField",
"id": "view",
"props": {
"name": "view",
"label": "View",
"defaultValue": "tree",
"onChange": "viewChanged()",
"options": [
{
"label": "Tree",
"value": "tree"
},
{
"label": "Columns",
"value": "columns"
},
{
"label": "Explorer",
"value": "explorer"
}
]
}
}
]
}
]
},
{
"type": "row",
"id": "row-buttons",
"children": [
{
"type": "column",
"id": "c-buttons",
"props": {
"className": "d-flex flex-wrap gap-2 mb-2"
},
"children": [
{
"type": "ButtonField",
"id": "add",
"props": {
"text": "+ Add to selected folder",
"variant": "outline-success",
"onClick": "addItem()"
}
},
{
"type": "ButtonField",
"id": "rename",
"props": {
"text": "Rename selected",
"variant": "outline-primary",
"onClick": "renameSelected()"
}
},
{
"type": "ButtonField",
"id": "delete",
"props": {
"text": "Delete selected",
"variant": "outline-danger",
"onClick": "deleteSelected()"
}
},
{
"type": "ButtonField",
"id": "goto",
"props": {
"text": "Go to dates.js",
"variant": "outline-secondary",
"onClick": "goToDates()"
}
},
{
"type": "ButtonField",
"id": "checked",
"props": {
"text": "Show checked",
"variant": "outline-secondary",
"onClick": "showChecked()"
}
}
]
}
]
},
{
"type": "Tree",
"id": "project",
"props": {
"title": "my-app",
"nodes": [
{
"id": "src",
"label": "src",
"expanded": true,
"children": [
{
"id": "src/components",
"label": "components",
"expanded": true,
"children": [
{
"id": "src/components/Button.js",
"label": "Button.js",
"size": 2310
},
{
"id": "src/components/Card.js",
"label": "Card.js",
"size": 1874
},
{
"id": "src/components/Modal.js",
"label": "Modal.js",
"size": 4120,
"badge": "new"
}
]
},
{
"id": "src/utils",
"label": "utils",
"children": [
{
"id": "src/utils/format.js",
"label": "format.js",
"size": 980
},
{
"id": "src/utils/dates.js",
"label": "dates.js",
"size": 1430
}
]
},
{
"id": "src/index.js",
"label": "index.js",
"size": 640
}
]
},
{
"id": "public",
"label": "public",
"children": [
{
"id": "public/index.html",
"label": "index.html",
"size": 1210
},
{
"id": "public/logo.png",
"label": "logo.png",
"size": 15086
}
]
},
{
"id": "config",
"label": "config",
"icon": "⚙️",
"children": [
{
"id": "config/prod.json",
"label": "prod.json",
"size": 310,
"disabled": true,
"description": "read-only"
}
]
},
{
"id": "package.json",
"label": "package.json",
"size": 1532
},
{
"id": "README.md",
"label": "README.md",
"size": 4890
}
],
"height": 330,
"checkboxes": true,
"cascadeCheck": true,
"showLines": true,
"showCount": true,
"draggable": true,
"editable": true,
"searchable": false,
"filters": [
{
"id": "js",
"label": ".js only",
"when": {
"field": "ext",
"equals": "js"
}
}
],
"contextMenu": [
{
"label": "Rename",
"command": "rename"
},
{
"label": "New file here",
"action": "newFileHere()",
"when": {
"field": "branch",
"equals": true
}
},
{
"divider": true
},
{
"label": "Delete",
"action": "deleteNode()"
}
],
"onSelect": "selected()",
"onExpand": "toggled()",
"onCollapse": "toggled()",
"onCheck": "checked()",
"onActivate": "opened()",
"onMove": "moved()",
"onRename": "renamed()",
"onNodeFocus": "focused()"
}
},
{
"type": "P",
"id": "status",
"props": {
"className": "small text-body-secondary mt-2",
"text": "Select, check, drag, double-click or right-click a node."
}
}
]Options used here
| Option | What it does |
|---|---|
nodes | [{ id, label, children, expanded, icon, badge, description, disabled }]. |
view / views | tree, explorer, columns. |
selectionMode | none, single, multiple (Ctrl / Shift). |
checkboxes / cascadeCheck | Checkboxes; folders check their children. |
showLines / showIcons / showCount | Guide lines, icons, child counts. |
draggable / editable | Drag to move; rename with F2. |
contextMenu | { label, action } or { label, command: "rename" | "open" | "expand" | "reload" | "delete" }, when, divider. |
filters / searchable | Filter chips (when on node fields, ext is filled in) and a search box. |
Events
| Event | When it runs | Your action receives |
|---|---|---|
onSelect | Selection changes. | { node, selected, nodes } |
onExpand / onCollapse | A folder opens / closes. | { node, id, path, level } |
onCheck | A checkbox changes. | { node, checked, checkedIds, checkedNodes } |
onActivate | Double-click / Enter on a file. | { node } |
onMove | A node is dropped. | { node, target, position, parentId, index } — return false to refuse |
onRename | A name is edited. | { node, name, previous } — return false to refuse |
onNodeFocus / onNodeClick / onNodeDoubleClick / onContextMenu / onDelete | Focus, clicks, right-click, Delete key. | { node } (onDelete: { ids, nodes }) |
Tips
- Keyboard: ↑ ↓ to move, → / ← to open / close, Enter to open, Space to select or check, * to open siblings, F2 to rename, type letters to jump.