# react-dnd-treeview: a headless tree component where you render the nodes

> The package gives you a drag and drop tree for React with no styling of its own, so every node is rendered through a render prop, and the drag layer comes from react-dnd with a choice of pointer, touch or combined backends.

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

- Repository: https://github.com/minop1205/react-dnd-treeview
- Stars: 606 · Forks: 77
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/minop1205-react-dnd-treeview

## A headless component: the tree renders nothing until you do

The description calls it a draggable and droppable React treeview component where render props create each node freely, and the repository topics list it as a headless component. That single word decides what the package is and is not.

A headless component ships behaviour and no appearance. It computes the tree, it knows which node is open, it knows where a drag started and where it was dropped, and it hands all of that to you through a function. The styling, the icons, the expand chevrons, the spacing, the file type artwork, all of that is your code. The examples in the documentation use MUI components, and the documentation is explicit that TreeView does not depend on MUI, so you can use another library or your own components instead.

For a team that has a design system, this is the point. You get a tree that behaves correctly, including the awkward parts of drag and drop over nested nodes, without inheriting a look and feel you would have to override. The cost is that you write the rendering yourself, and the component API table in the documentation is long, which is the usual sign of a component with a wide surface.

The interactive documentation is published as a Storybook at the project pages, and the repository carries a .storybook directory along with a Storybook setup in its dev dependencies.

## The data model is a flat array with parent ids

The tree is passed as one flat array of node objects, and the hierarchy is expressed by the parent property. This is the core design decision and it is worth understanding before anything else, because it determines how you load, update and persist your data.

```json
[
  {
    "id": 1,
    "parent": 0,
    "droppable": true,
    "text": "Folder 1"
  },
  {
    "id": 2,
    "parent": 1,
    "text": "File 1-1"
  },
```

The id is a number or a string and is required, as is the parent id, and the root nodes simply point at a parent id of zero. The text property is the node label and is also required. The droppable property is a boolean, false by default, and it controls two things at once: whether the node accepts child nodes, and whether other nodes can be dropped onto it. Any node with droppable true can hold children and can receive a drop.

There is also a data property of any type, defaulting to undefined, which exists so you can attach your own fields to a node and have them available in the render props. The documented example attaches a file type and a file size to file nodes, and the same information then reaches your render function without the component needing to know anything about files.

The consequence for an application is that your state is a list, not a tree. Adding a node means pushing an object and setting its parent id, and removing a node means finding and removing its descendants, which is your code rather than the component's.

## Drag and drop is delegated to react-dnd, and you choose the backend

The tree does not implement dragging. It is built on react-dnd, and the component is wrapped in a DndProvider from that library, so the tree participates in a drag and drop context that you configure.

The default in the getting started example is MultiBackend, which the documentation describes as a backend to support both touch and pointer devices. If you only need one of the two, the documentation points at the backend provided by react-dnd-html5-backend or by react-dnd-touch-backend instead, and the tree is used the same way in that case.

```js
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";

function App() {
  return (
    <DndProvider backend={HTML5Backend}>
      <Tree {...someProps}> />
    </DndProvider>
  );
}
```

The three backends accept the backend options defined in react-dnd, and there is one asymmetry worth knowing: for the HTML5 backend only the rootElement option is available, while the touch backend has a wider set of options described in the react-dnd documentation.

That is the whole integration story. Your application already has a DndProvider, or you add one, and the tree becomes draggable inside it. The tree is also not a leaf in the dependency tree: it brings react-dnd-html5-backend and react-dnd-touch-backend along as real dependencies, plus dnd-multi-backend for the combined mode.

## Installing the package and rendering the first tree

The install step is two packages, and it is worth noticing that the tree is published under a scope.

```bash
$ npm i react-dnd @minoru/react-dnd-treeview
```

The published package name is @minoru/react-dnd-treeview, with the author and the scope both coming from the maintainer, and react-dnd is a peer you install yourself because the DndProvider has to be configured by the application.

The usage example in the documentation keeps the tree data in state and replaces it on drop.

```js
    <DndProvider backend={MultiBackend} options={getBackendOptions()}>
      <Tree
        tree={treeData}
        rootId={0}
        onDrop={handleDrop}
        render={(node, { depth, isOpen, onToggle }) => (
          <div style={{ marginLeft: depth * 10 }}>
            {node.droppable && (
              <span onClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>
            )}
            {node.text}
          </div>
        )}
      />
    </DndProvider>
```

The shape of the API is the shape of the component. The tree prop takes the flat array, the rootId prop tells the component which id is the root, and the onDrop prop receives the new tree data when a node has been moved. The render prop receives the node and a set of helpers, and the example uses depth to indent, isOpen to decide whether to draw an expanded or collapsed marker, and onToggle as the click handler for that marker.

The node's droppable property doubles as the signal for whether to draw the marker at all, which is why the example only renders a toggle for droppable nodes.

## What the dependency list says about the implementation

The package manifest is a good place to look for the parts of the behaviour that are not described in prose.

framer-motion is a runtime dependency, so the component animates something, and in a tree view the obvious candidate is the expansion and collapse of a branch. dnd-multi-backend is a dependency, which is how the combined pointer and touch mode is implemented. @juggle/resize-observer is a dependency, which is what lets the component measure its container and react to a panel being resized. react-use-measure is a dependency for the same general purpose. And react-dnd-html5-backend and react-dnd-touch-backend are both direct dependencies, so both single backend modes work out of the box.

On the build side, the project uses Rollup, with a rollup.config.js and separate tsconfig files for the build and for the editor, and the package is published as an ES module with the type field set to module, the entry point at dist/index.js and the type declarations at dist/index.d.ts, with only the dist directory included in the published files.

The tooling is modern as well. Biome handles linting and formatting through a biome.json file, tests run on Vitest with a vitest.config.ts and Playwright for browser testing, and the storybook packages are used for the documentation site that carries the interactive examples.

## Where react-dnd-treeview is the wrong tool

There are four situations where this package does not fit.

The first is a very large tree. Nothing in the documentation mentions virtualisation, and the data model is a flat array that the component reads and writes. A tree with tens of thousands of nodes in the DOM is a rendering problem you will solve yourself, and the component will not solve it for you.

The second is a project that does not want react-dnd. The tree is built on it and cannot be used without it, and if your application already uses a different drag and drop library, having two is a cost rather than a convenience. The dependency footprint is not small either, with framer-motion and two backends arriving with the package.

The third is a codebase that has not standardised on a drag approach. Choosing MultiBackend, the HTML5 backend or the touch backend is a real decision, and the HTML5 backend has fewer options available, so the choice is not purely about device coverage.

The fourth is a team that wants a finished component. A headless component means you write the expand arrow, the file icons, the drag preview, the selection styling and the empty state. If the goal is a tree that looks like the ones in the examples on day one, this package is the wrong starting point, because the visual layer in the examples is example code, not part of the package.

## Version 3.5.4, the migration file, and the MIT licence

The published version is 3.5.4, and the licence is MIT, with the repository carrying a LICENSE file. That is a permissive grant, so the code can be used in a commercial product, modified and redistributed, provided the notice is kept, and this is not legal advice.

The maintenance picture is mixed and worth reading carefully. The most recent release is v3.5.4, published on 2026-05-19, and the last push to the repository was the same day. Before that came v3.5.3 on 2025-07-13 and v3.5.2 on 2025-04-21, so there was a gap of about ten months between the two most recent releases. The repository is not archived and the default branch is named next, which is a common convention for a project where the next major version is being prepared.

The presence of a MIGRATION.md file at the root is the important signal for an adopter. The documentation points to it for information on breaking changes and migrations between major versions, which tells you the project has had API changes at the major level and expects consumers to do migration work.

For a team putting this into a product, the safe order is to pin to 3.5.4, read MIGRATION.md for the 2.x to 3.x changes if that is a jump you are making, and keep the version pinned until you have decided to take the next major. A headless component that you have written your own render functions against is exactly the kind of code where a major version migration touches a lot of your files.

## Conclusion

react-dnd-treeview is the right component for a React application that needs a reorderable hierarchy, such as a file tree or a settings panel, and it suits teams that want to own every pixel of the node rendering. It is the wrong choice for a large tree that needs virtualisation, for a codebase that has no react-dnd dependency and does not want one, and for a project that needs the drag interaction to work in every browser without choosing a backend. Before adopting, render the tree with the default droppable rules, confirm that the react-dnd backend you pick matches the devices your users have, and read MIGRATION.md before crossing a major version, since the package sits at 3.5.4 and its major versions have carried breaking changes.

## FAQ

### What is react-dnd-treeview?

It is a draggable and droppable React treeview component that uses render props so you can create each node freely. The project topics describe it as a headless component, and the documentation states that TreeView does not depend on MUI even though some examples use it.

### How do I install react-dnd-treeview?

The getting started section gives the command npm i react-dnd @minoru/react-dnd-treeview, so the package is published under the @minoru scope and react-dnd is installed alongside it because the tree needs a DndProvider.

### What data structure does react-dnd-treeview expect?

It expects a flat array of node objects where each node has an id, a parent id and a text label, with root nodes pointing at a parent id of zero. The optional droppable flag controls whether a node accepts children and receives drops, and the optional data property carries your own fields into the render props.

### How does react-dnd-treeview handle touch screens?

MultiBackend is the backend to support both touch and pointer devices, and the package depends on dnd-multi-backend along with react-dnd-html5-backend and react-dnd-touch-backend. If you only need one kind of device you can use the HTML5 or the touch backend directly, where only the rootElement option is available for the HTML5 backend.

### What changed between major versions of react-dnd-treeview?

The project keeps a Migration Guide at MIGRATION.md in the repository root for breaking changes and migrations between major versions, and the current published version is 3.5.4. There is also a CHANGELOG.md in the repository.

## Sources

- [Issues](https://github.com/minop1205/react-dnd-treeview/issues)
- [License: MIT](https://github.com/minop1205/react-dnd-treeview/blob/next/LICENSE)
- [minop1205/react-dnd-treeview on GitHub](https://github.com/minop1205/react-dnd-treeview)
- [README](https://github.com/minop1205/react-dnd-treeview/blob/next/README.md)
- [Releases](https://github.com/minop1205/react-dnd-treeview/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/minop1205-react-dnd-treeview
