Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

React DnD TreeView

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

react-dnd-treeview

Demo

Examples (on CodeSandbox)

Some of the examples below use Material-UI components, but TreeView does not depend on Material-UI, so you can use other libraries or your own custom components.

Getting Started

Installation

$ npm install --save @minoru/react-dnd-treeview

Usage

import{Tree}from"@minoru/react-dnd-treeview";
...
const[treeData,setTreeData]=useState(initialData);consthandleDrop=(newTreeData)=>setTreeData(newTreeData);<Treetree={treeData}rootId={0}onDrop={handleDrop}render={(node,{depth, isOpen, onToggle})=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

Data Structure

In order to display the tree,
we need to pass the following data to the Tree component

Basic example

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"
}
]

Optional data

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"
}
}
]

Node Properties

KeyTypeRequiredDefaultDescription
idnumber | stringyes-Identifier of each node
parentnumber | stringyes-Parent id of each node
textstringyes-Node label
droppablebooleannofalseIf true, child nodes will be accepted and it will be able to drop other node
dataanynoundefinedAdditional data to be injected into each node.
These data are available in the render props.

Component API

PropsTypeRequiredDefaultDescription
treearrayyesThe data representing the tree structure. An array of node data.
rootIdnumber | stringyesThe id of the root node. It is the parent id of the shallowest node displayed in the tree view.
classesobjectnoundefinedA set of CSS class names to be applied to a specific area in the tree view.
See the Component Styling section for more information.
listComponentstringnoulHTML tag for list.
listItemComponentstringnoliHTML tag for list items.
renderfunctionyesThe render function of each node.
Please refer to the Render prop section for more details about the render functions.
dragPreviewRenderfunctionnoundefinedRender 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.
onDropfunctionyesCallback 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.
canDropfunctionnoundefinedA callback function to determine if a given node can be dropped to another node.
If nothing is returned (or if undefined is returned), the default rules are followed.
If it returns true or false, the default rules will be overridden and the dropable properties of each node will not be referenced.
This callback takes the current tree and the same option object that is passed to the onDrop callback.
See the canDrop callback section for more information.
canDragfunctionnoundefinedCallback function which should return true or false depending on if a give node should be draggable.
By default, all nodes are draggable.
sortfunction | booleannotrueThis property controls the order of the child nodes.
By default (true), they are sorted by the text property of each node.
If false, sorting is disabled. In this case, the nodes will follow the order of the array passed to the tree property.
It is also possible to customize the sorting by passing a callback function.
insertDroppableFirstbooleannotrueSpecifies whether droppable nodes should be placed first in the list of child nodes.
placeholderRenderfunctionnoundefinedRender function for the drop destination placeholder. By default, placeholder is not displayed.
See the Manual sort with placeholder section for more information on using placeholder.
placeholderComponentstringnoliHTML tag for placeholder.
dropTargetOffsetnumberno0Effective drop range of a dropable node. It is specified in pixels from the top or bottom of the node.
Used to insert a node anywhere using placeholders.

See the Manual sort with placeholder placeholder section for more information on using placeholder.
initialOpenboolean | arraynofalseIf true, all parent nodes will be initialized to the open state.
If an array of node IDs is passed instead of the boolean value, only the specified node will be initialized in the open state.

Render prop

To render each tree node, please pass a render function to the render property.

<Tree{...props}render={(node,{ depth, isOpen, draggable, onToggle })=>(<divstyle={{marginLeft: depth*10}}>{node.droppable&&(<spanonClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>)}{node.text}</div>)}/>

The arguments passed to the render function are as follows

NameTypeDescription
dataobjectNode data. (an element in the tree data array)
options.depthnumberThe depth of the node hierarchy.
options.isOpenbooleanThe open and closed state of the node.
If droppable is not true, isOpen is always false.
options.draggablebooleanIndicates whether this node is draggable or not.
options.hasChildbooleanFlag indicating whether or not the node has children. It is true if the node has children, false otherwise.
options.onTogglefunctionAn event handler for the open/close button of a node.

Dragging Preview

By default, the drag preview is a screenshot of a DOM node.
The dragPreviewRender property allows you to display a custom React component instead of a screenshot.

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.

<Tree{...props}dragPreviewRender={(monitorProps)=>{constitem=monitorProps.item;return(<div><p>{item.text}</p></div>);}}/>

The data passed to dragPreviewRender contains the following properties

NameTypeDescription
itemobjectNode data. (an element in the tree data array)
It also includes the ref property, which is a reference to the HTML element to be dragged.
clientOffsetobjectThe client offset of the pointer during the dragging operation.
It is in the format of {x: number, y: number}.
If the item is not being dragged, it is set to null.

onDrop callback

If the tree is modified by drag-and-drop, the changes can be retrieved by the onDrop callback.

const[treeData,setTreeData]=useState(initialTreeData);consthandleDrop=(newTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{// Do somethingsetTreeData(newTree);};return<Tree{...props}tree={treeData}onDrop={handleDrop}/>;

The arguments passed to the onDrop callback function are as follows

NameTypeDescription
newTreearrayThis data represents the updated TreeView.
To redraw the modified TreeView, you need to set this data to the tree property.
options.dragSourceIdnumber | stringnode id of the dragging source
options.dropTargetIdnumber | stringnode id of the drop destination.
If the drop destination is the root node, it will be the value of the rootId property.
options.dragSourceobjectnode item of the dragging source
options.dropTargetobject | undefinednode item of the drop destination.
If the drop destination is the root node, it will be undefined

canDrop callback

By default, it allows dropping to any dropable node (or root node) except its own descendants. This callback can override the default rules.

If it returns nothing or returns undefined, the default rules will be applied. If it returns a boolean value, it will override the default rules and the droppable property of each node will no longer be referenced.

If it returns false and the user drops the dragged node, no action will be taken and the onDrop callback will not be fired.

This callback takes the same parameters as the onDrop callback, but the first parameter specifies the current tree.

constcanDrop=(currentTree,{ dragSourceId, dropTargetId, dragSource, dropTarget })=>{returntrue;// orreturnfalse;// orreturn;// orreturnundefined;};return<Tree{...props}tree={treeData}canDrop={canDrop}/>;

NOTE:
When overriding the default rules by returning true or false, be careful of inconsistencies in the tree structure.
For example, if you allow dropping from a parent node to a child node as shown in the figure below, inconsistency will occur and the tree will collapse.

malformed tree

Manual sort with placeholder

By default, nodes are automatically sorted and cannot be sorted manually, but by combining some APIs, you can sort them manually and display placeholders as follows.

placeholder_sample

The following is an example (excerpt) of the implementation of manual sort of nodes and placeholder display.

import{CustomPlaceholder}from"./CustomPlaceholder";importstylesfrom"./App.module.css";functionApp(){const[treeData,setTreeData]=useState(SampleData);consthandleDrop=(newTree)=>setTreeData(newTree);<Tree{...props}tree={treData}onDrop={handleDrop}classes={{placeholder: styles.placeholder,}}sort={false}insertDroppableFirst={false}canDrop={(tree,{ dragSource, dropTargetId })=>{if(dragSource?.parent===dropTargetId){returntrue;}}}dropTargetOffset={5}placeholderRender={(node,{ depth })=>(<CustomPlaceholdernode={node}depth={depth}/>)}/>;}

Component Styling

You are free to define the styling of individual nodes in the tree in your Render props, but the rest of the tree can be styled by specifying the CSS class name for the classes property.

<Tree{...props}classes={{root: "my-root-classname",dragOver: "my-dragover-classname",}}/>

You can use the following keys for the objects you pass to the classes property. Neither key is required.

NameDescription
rootCSS class name to give to the top-level container element (by default, ul tag) that wraps all nodes.
containerCSS class name to give to the element wrapping the list of nodes of the same hierarchy (by default, ul tag).
dropTargetCSS class name to give to the area that can be dropped during a node dragging operation.
draggingSourceCSS class name to give to the node during the dragging operation.
placeholderCSS class name to give to the element wrapping the placeholder (by default, li tag).

Usage to open / close methods

The open/close status of a node is managed within the Tree component, but the methods for opening and closing nodes are public, so they can be controlled from outside the Tree component.

constref=useRef(null);consthandleOpenAll=()=>ref.current.openAll();consthandleCloseAll=()=>ref.current.closeAll();// open /close method can be passed a node ID or an array of node IDsconsthandleOpen=(nodeId)=>ref.current.open(nodeId);consthandleClose=(nodeId)=>ref.current.close(nodeId);<Treeref={ref}{...props}><buttononClick={handleOpenAll}>Open All Folders</button><buttononClick={handleCloseAll}>Close All Folders</button><buttononClick={handleOpen}>Open specific folder(s)</button><buttononClick={handleClose}>Close specific folder(s)</button>

License

MIT.

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages