Direactree

Props & callbacks

A complete reference for every Direactree prop, callback payload, default value, type, behavior rule, and common use case.

Props overview

| Prop | Type | Default | Purpose | | --- | --- | --- | --- | | structure | TreeNode[] | Required | Directory nodes rendered by the component. | | className | string | — | Adds a class to the component root. | | indent | number | 20 | Horizontal offset between hierarchy levels. | | showToolbox | boolean | true | Shows create, rename, and delete controls. | | toolboxIcons | ToolboxIcons | Built-in icons | Replaces individual toolbox icons. | | toolboxSticky | boolean | false | Keeps the toolbox visible while its container scrolls. | | allowDragAndDrop | boolean | true | Enables node movement. | | isAllExpanded | boolean | false | Expands every folder for the initial render. | | onCreateFolder | (parent: NodePath \| null) => void | — | Reports the create-folder action. | | onCreateFile | (parent: NodePath \| null) => void | — | Reports the create-file action. | | onRename | (node: NodePath) => void | — | Reports the rename action. | | onDelete | (node: NodePath) => void | — | Reports the delete action. | | onSave | (props: SaveProps) => void | — | Reports a confirmed create or rename. | | onSelectedNodeChange | (node: NodePath \| null) => void | — | Reports selection changes. | | onNodeMove | (node: TreeNode, target: TreeNode) => void | — | Reports a valid drag-and-drop move. |

structure

Type
TreeNode[]
Required
Yes

structure is the source hierarchy rendered by Direactree. Root items are array entries; nested items live in a folder's children array.

type TreeNode = {
  id: string;
  name: string;
  type: "file" | "folder";
  children?: TreeNode[];
  isExpanded?: boolean;
};

Example structure:

const structure: TreeNode[] = [
  {
    id: "0",
    name: "C:/",
    type: "folder",
    children: [
      {
        id: "1",
        name: "Users",
        type: "folder",
        children: [
          {
            id: "2",
            name: "John Doe",
            type: "folder",
            children: [
              {
                id: "3",
                name: "Documents",
                type: "folder",
                children: [
                  { id: "4", name: "sample.tsx", type: "file" },
                ],
              },
              { id: "5", name: "logs.txt", type: "file" },
            ],
          },
        ],
      },
    ],
  },
];

<Direactree structure={structure} />;

children is optional because files do not contain nodes and empty folders may omit it. Supplying children: [] for folders is also valid. isExpanded controls a folder's initial expansion individually; isAllExpanded can override the initial behavior for the whole tree.

TRY ITStructure input

Change the TreeNode array and see the rendered hierarchy update.

structure
[
  {
    "id": "0",
    "name": "Desktop",
    "type": "folder",
    "children": [
      {
        "id": "1",
        "name": "Projects",
        "type": "folder",
        "children": [
          {
            "id": "1.1",
            "name": "Web Applications",
            "type": "folder",
            "children": [
              {
                "id": "sample.txt",
                "name": "project-notes.txt",
                "type": "file"
              },
              {
                "id": "example.json",
                "name": "config.json",
                "type": "file"
              },
              {
                "id": "sample.ts",
                "name": "utils.ts",
                "type": "file"
              }
            ]
          }
        ]
      },
      {
        "id": "2",
        "name": "Documents",
        "type": "folder",
        "children": [
          {
            "id": "REST-API.md",
            "name": "REST-API.md",
            "type": "file"
          }
        ]
      },
      {
        "id": "DireactreeUsage.tsx",
        "name": "DireactreeUsage.tsx",
        "type": "file"
      }
    ]
  }
]
  • ►Desktop

Display and interaction

indent

Type
number
Required
No
Default
20

Controls the horizontal indentation between tree levels. The accepted range is 8–50:

  • Values below 8 are normalized to 8.
  • Values above 50 are normalized to 50.
<Direactree structure={structure} indent={28} />

Use a smaller value in narrow sidebars and a larger value when hierarchy depth should be visually prominent.

TRY ITIndent spacing

Move the slider to compare compact and spacious hierarchy levels.

  • ►Desktop

isAllExpanded

Type
boolean
Required
No
Default
false

Determines whether all folders are expanded on the initial render.

<Direactree structure={structure} isAllExpanded />

This is useful for small trees where users should see the complete hierarchy immediately. For large structures, keep the default to avoid overwhelming the interface.

TRY ITInitial expansion

The tree remounts when the value changes because this prop controls the initial render.

  • ►Desktop

allowDragAndDrop

Type
boolean
Required
No
Default
true

Enables or disables moving files and folders by dragging.

<Direactree structure={structure} allowDragAndDrop={false} />

Set it to false for read-only explorers or when your backend does not support re-parenting. This setting does not hide the toolbox; use showToolbox separately.

TRY ITDrag and drop

Toggle movement, then drag a node onto a folder.

  • ►Desktop
last valid move
null

showToolbox

Type
boolean
Required
No
Default
true

Controls the built-in create-folder, create-file, rename, and delete actions.

<Direactree structure={structure} showToolbox={false} />

Disable it when the tree is only used for navigation or selection. To make a tree completely read-only, combine showToolbox={false} and allowDragAndDrop={false}.

TRY ITToolbox visibility

Hide or reveal the built-in create, rename, and delete controls.

  • ►Desktop

toolboxSticky

Type
boolean
Required
No
Default
false

Keeps the toolbox visible while the tree's scroll container moves.

<div style={{ height: 320, overflow: "auto" }}>
  <Direactree
    structure={structure}
    toolboxSticky
    isAllExpanded
  />
</div>

Use it for tall trees inside a height-constrained panel. It has no visible effect when the surrounding content does not scroll.

TRY ITSticky toolbox

Scroll inside the constrained area and compare the toolbox position.

  • ►Desktop

toolboxIcons

Type
ToolboxIcons
Required
No

Replaces any built-in toolbox icon with a ReactNode. Every field is optional, so icons can be changed individually.

type ToolboxIcons = {
  createFolder?: React.ReactNode;
  createFile?: React.ReactNode;
  rename?: React.ReactNode;
  delete?: React.ReactNode;
};
const toolboxIcons = {
  createFolder: <FolderPlusIcon />,
  createFile: <FilePlusIcon />,
  rename: <EditIcon />,
  delete: <TrashIcon />,
};

<Direactree
  structure={structure}
  toolboxIcons={toolboxIcons}
/>;

Use custom icons to match an existing design system. Icon nodes should have an accessible name when their visual meaning is not accompanied by text.

TRY ITCustom toolbox icons

Switch between Direactree defaults and custom React nodes.

  • ►Desktop

className

Type
string
Required
No

Adds a custom class name to the Direactree root element for layout-level customization.

<Direactree structure={structure} className="project-explorer" />

Prefer the component's public props for behavior and use className for spacing, sizing, and placement in your own layout.

TRY ITCustom root class

Apply a presentation class without changing Direactree behavior.

  • ►Desktop

Event callbacks

Callback props make it possible to observe interaction and synchronize Direactree with application state or a backend.

NodePath is used by selection and toolbox callbacks:

type NodePath = {
  name: string;
  id: string;
  type: "file" | "folder";
  parent: NodePath | null;
};

Unlike TreeNode, NodePath describes ancestry through its recursive parent field. The root node has parent: null.

onSelectedNodeChange

Type
(node: NodePath | null) => void
Required
No

Called when a user selects a node or when selection becomes empty. The callback receives the selected path or null.

const [selectedNode, setSelectedNode] = useState<NodePath | null>(null);

<Direactree
  structure={structure}
  onSelectedNodeChange={setSelectedNode}
/>;

Use this callback to show a file preview, populate a detail panel, or enable actions for the current node.

TRY ITSelection callback

Select a file or folder to inspect the complete NodePath.

  • ►Desktop
selectedNode
null

onNodeMove

Type
(sourceNode: TreeNode, targetNode: TreeNode) => void
Required
No

Called after a user moves a node onto a valid target folder. The first argument is the moved node and the second is its destination.

const [lastMove, setLastMove] = useState<{
  source: TreeNode;
  target: TreeNode;
} | null>(null);

function handleNodeMove(source: TreeNode, target: TreeNode) {
  setLastMove({ source, target });
}

<Direactree structure={structure} onNodeMove={handleNodeMove} />;

The callback is not called when:

  • The source is dropped onto itself.
  • A folder is dropped into one of its own descendants.
  • The destination is a file.

Set allowDragAndDrop={false} when moves should not be available at all.

TRY ITMove callback

Drag a node onto a valid folder to inspect source and target payloads.

  • ►Desktop
sourceNode
null
targetNode
null

Toolbox action callbacks

Type
NodePath callbacks
Required
No
onCreateFolder?: (parentNode: NodePath | null) => void;
onCreateFile?: (parentNode: NodePath | null) => void;
onRename?: (node: NodePath) => void;
onDelete?: (node: NodePath) => void;
  • onCreateFolder fires when folder creation starts and receives the selected parent folder.
  • onCreateFile fires when file creation starts and receives the selected parent folder.
  • onRename receives the node whose name is about to be edited.
  • onDelete receives the node requested for deletion.

If no node is selected, the create callbacks receive null. Use this signal to create the new file or folder at the root.

function handleCreateFolder(parent: NodePath | null) {
  console.log("Create folder under", parent?.id ?? "root");
}

function handleCreateFile(parent: NodePath | null) {
  console.log("Create file under", parent?.id ?? "root");
}

function handleRename(node: NodePath) {
  console.log("Rename", node.id);
}

function handleDelete(node: NodePath) {
  console.log("Delete", node.id);
}

<Direactree
  structure={structure}
  onCreateFolder={handleCreateFolder}
  onCreateFile={handleCreateFile}
  onRename={handleRename}
  onDelete={handleDelete}
/>;
TRY ITToolbox action callbacks

Select a node and use a toolbox icon to inspect the action and NodePath.

  • ►Desktop
last toolbox action
null

onSave

Type
(saveProps: SaveProps) => void
Required
No

Called when the user confirms the name in the editable area. It represents the completed create or rename input, not merely the initial toolbox click.

type SaveProps = {
  newName: string;
  selectedNode: NodePath | null;
  actionType: "create" | "edit";
  createType?: "folder" | "file";
};

Payload meaning:

| Field | Meaning | | --- | --- | | newName | The value confirmed by the user. | | selectedNode | The creation parent or node being renamed. | | actionType | create for a new node, edit for a rename. | | createType | folder or file during creation; omitted for editing. |

const [lastSave, setLastSave] = useState<SaveProps | null>(null);

function handleSave(saveProps: SaveProps) {
  setLastSave(saveProps);
  // Persist to your API or update the TreeNode[] here.
}

<Direactree structure={structure} onSave={handleSave} />;
TRY ITSave callback

Start a create or rename action, enter a name, and confirm it.

  • ►Desktop
saveProps
null

Complete types

These are the public shapes used by the component:

interface TreeNode {
  id: string;
  name: string;
  type: "file" | "folder";
  children?: TreeNode[];
  isExpanded?: boolean;
}

type NodePath = {
  name: string;
  id: string;
  type: "file" | "folder";
  parent: NodePath | null;
};

interface SaveProps {
  newName: string;
  selectedNode: NodePath | null;
  actionType: "create" | "edit";
  createType?: "folder" | "file";
}

interface ToolboxIcons {
  createFolder?: React.ReactNode;
  createFile?: React.ReactNode;
  rename?: React.ReactNode;
  delete?: React.ReactNode;
}

Import them directly from the package:

import type {
  DireactreeProps,
  NodePath,
  SaveProps,
  ToolboxIcons,
  TreeNode,
} from "direactree";