A draggable and droppable React treeview component.
You can use render props to create each node freely.

Some of the examples below use MUI(Material-UI) components, but TreeView does not depend on MUI, so you can use other libraries or your own custom components.
https://minop1205.github.io/react-dnd-treeview/
See Migration Guide for information on breaking changes and migrations between major versions.
$ npm i react-dnd @minoru/react-dnd-treeview
import { useState } from "react";
import {
Tree,
getBackendOptions,
MultiBackend,
} from "@minoru/react-dnd-treeview";
import { DndProvider } from "react-dnd";
import initialData from "./sample-default.json";
function App() {
const [treeData, setTreeData] = useState(initialData);
const handleDrop = (newTreeData) => setTreeData(newTreeData);
return (
<DndProvider backend={MultiBackend} options={getBackendOptions()}>
<Tree
tree={treeData}
rootId={0}
onDrop={handleDrop}
render={(node, { depth, isOpen, onToggle }) => (
{node.droppable && (
<span onClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>
)}
{node.text}
)}
/>
</DndProvider>
);
}
MultiBackend is a backend to support both touch and pointer devices. If you only need support for one or the other, you can also use the backend provided by react-dnd-html5-backend or react-dnd-touch-backend.
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
function App() {
return (
<DndProvider backend={HTML5Backend}>
<Tree {...someProps}> />
</DndProvider>
);
}
import { DndProvider } from "react-dnd";
import { TouchBackend } from "react-dnd-touch-backend";
function App() {
return (
<DndProvider backend={TouchBackend}>
<Tree {...someProps}> />
</DndProvider>
);
}
HTML5Backend, TouchBackend and MultiBackend allow setting the BackendOptions defined in react-dnd.
For more information on TouchBackend, please see here. (For the HTML5Backend option, only the rootElement option is available.)
import { DndProvider } from "react-dnd";
import { HTML5Backend, HTML5BackendOptions } from "react-dnd-html5-backend";
import {TouchBackend, TouchBackendOptions} from "react-dnd-touch-backend"
import {Tree, MultiBackend, getBackendOptions} from "@minoru/react-dnd-treeview"
const touchOptions: Partial<TouchBackendOptions> = {
// some options
};
const html5Options: Partial<HTML5BackendOptions> = {
rootElement: document.body,
// some options
};
const multiOptions = {
touch: touchOptions,
html5: html5Options,
}
function App() {
return (
<DndProvider
backend={MultiBackend}
options={getBackendOptions(multiOptions)}
// or
// backend={HTML5Backend}
// options={html5Options}
// or
// backend={TouchBackend}
// options={touchOptions}
>
<Tree {...someProps}> />
</DndProvider>
);
}
To display the treeview, pass data with the following structure to the tree property of the Tree component.
The minimal data structure for representing the tree is shown in the following example
[
{
"id": 1,
"parent": 0,
"droppable": true,
"text": "Folder 1"
},
{
"id": 2,
"parent": 1,
"text": "File 1-1"
},
{
"id": 3,
"parent": 1,
"text": "File 1-2"
},
{
"id": 4,
"parent": 0,
"droppable": true,
"text": "Folder 2"
},
{
"id": 5,
"parent": 4,
"droppable": true,
"text": "Folder 2-1"
},
{
"id": 6,
"parent": 5,
"text": "File 2-1-1"
}
]
If you want to pass custom properties to each node's rendering,
you can use the data property.
[
{
"id": 1,
"parent": 0,
"droppable": true,
"text": "Folder 1"
},
{
"id": 2,
"parent": 1,
"text": "File 1-1",
"data": {
"fileType": "csv",
"fileSize": "0.5MB"
}
},
{
"id": 3,
"parent": 1,
"text": "File 1-2",
"data": {
"fileType": "pdf",
"fileSize": "4.8MB"
}
},
{
"id": 4,
"parent": 0,
"droppable": true,
"text": "Folder 2"
},
{
"id": 5,
"parent": 4,
"droppable": true,
"text": "Folder 2-1"
},
{
"id": 6,
"parent": 5,
"text": "File 2-1-1",
"data": {
"fileType": "image",
"fileSize": "2.1MB"
}
}
]
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
| id | number | string |
✅ | - | Identifier of each node |
| parent | number | string |
✅ | - | Parent id of each node |
| text | string |
✅ | - | Node label |
| droppable | boolean |
false |
If true, child nodes will be accepted and it will be able to drop other node |
|
| data | any |
undefined |
Additional data to be injected into each node. |
These data are available in the render props. |
| Props | Type | Required | Default | Description |
|---|---|---|---|---|
| tree | array |
✅ | The data representing the tree structure. An array of node data. | |
| rootId | number | string |
✅ | The id of the root node. It is the parent id of the shallowest node displayed in the tree view. | |
| extraAcceptTypes | array |
[] |
If allowing drop from outside the tree, the drag type of the drag source. | |
| classes | object |
undefined |
A set of CSS class names to be applied to a specific area in the tree view. |
See the Component Styling section for more information. |
| listComponent | string | | ul | HTML tag for list. |
| listItemComponent | string | | li | HTML tag for list items. |
| render | function | ✅ | | The render function of each node.
Please refer to the Render prop section for more details about the render functions. |
| dragPreviewRender | function | | undefined | Render function for customizing the drag preview.
See the Dragging Preview section for more information on customizing the drag preview
NOTE:
The default preview is not displayed on touch devices. Therefore, if you want to support touch devices, please define a custom preview in dragPreviewRender. |
| onDrop | function | ✅ | | Callback function for when the state of the tree is changed.
The new data is passed as the argument.
See the onDrop callback section for more information. |
| onDragStart | function | | undefined | This event is fired when a node in the tree is started to be dragged. The event handler is passed the target node and a DragSourceMonitor object. |
| onDragEnd | function | | undefined | This event is fired when a node in the tree is finished being dragged. The event handler is passed the target node and a DragSourceMonitor object. |
| onChangeOpen | function | | undefined | Callback function to be called after the open/close state of a node is changed.
The function is passed an array o
$ claude mcp add react-dnd-treeview \
-- python -m otcore.mcp_server <graph>