react-d3-tree and react-treebeard are both React libraries designed to render hierarchical tree structures, but they serve different visualization needs. react-d3-tree focuses on creating SVG-based organizational charts and dendrograms using D3.js under the hood, offering high customization for static or semi-interactive diagrams. react-treebeard is built for rendering interactive file-system-like trees in the DOM, emphasizing features like expand/collapse animations, checkbox selection, and keyboard navigation for data grids or navigation menus.
When building React applications that display hierarchical data, developers often face a choice between diagrammatic representations (like org charts) and interactive navigation trees (like file explorers). react-d3-tree and react-treebeard address these two distinct use cases. While both handle tree structures, their underlying rendering engines, interaction models, and customization capabilities differ significantly. Let's compare how they tackle common engineering challenges.
react-d3-tree renders trees using SVG via D3.js.
// react-d3-tree: SVG-based rendering
import Tree from 'react-d3-tree';
const data = { name: 'CEO', children: [{ name: 'CTO' }] };
function OrgChart() {
return <Tree data={data} orientation='vertical' />;
}
react-treebeard renders trees using standard DOM elements (divs, spans).
// react-treebeard: DOM-based rendering
import { Treebeard } from 'react-treebeard';
const data = [{ name: 'root', children: [{ name: 'file.txt' }] }];
function FileExplorer() {
return <Treebeard data={data} onToggle={handleToggle} />;
}
react-d3-tree focuses on diagram navigation.
// react-d3-tree: Zoom and Pan support
<Tree
data={data}
zoomable={true}
translate={{ x: 100, y: 50 }}
onNodeClick={handleNodeClick}
/>
react-treebeard focuses on list navigation.
// react-treebeard: Selection and Toggle
<Treebeard
data={data}
onToggle={handleToggle}
onSelect={handleSelect}
decorators={customDecorators}
/>
react-d3-tree allows custom React components as nodes.
// react-d3-tree: Custom Node Element
const CustomNode = ({ nodeDatum }) => (
<div className="custom-node">
<img src={nodeDatum.avatar} />
<span>{nodeDatum.name}</span>
</div>
);
<Tree data={data} renderCustomNodeElement={CustomNode} />;
react-treebeard allows custom decorators and styling.
// react-treebeard: Custom Decorators
const decorators = {
Toggle: ({ style }) => <div style={{ ...style, background: 'blue' }} />
};
<Treebeard data={data} decorators={decorators} />;
Both packages expect a hierarchical data structure, but the specific shape varies slightly.
react-d3-tree expects a single root object with a children array. It is strict about this hierarchy for the D3 layout engine.react-treebeard expects an array of nodes (which can have a children array). It is more flexible for rendering multiple root trees.// react-d3-tree: Single Root Object
const d3Data = {
name: 'Root',
children: [{ name: 'Child 1' }]
};
// react-treebeard: Array of Roots
const treebeardData = [
{ name: 'Root 1', children: [] },
{ name: 'Root 2', children: [] }
];
react-d3-tree is generally well-maintained for its specific niche.
react-treebeard has had periods of low maintenance.
react-complex-tree if long-term support is critical.// Warning: Always verify maintenance status before installation
// npm view react-treebeard time.modified
// npm view react-d3-tree time.modified
Despite their differences, both libraries solve the problem of displaying hierarchical data in React.
// Both handle recursive children arrays
const node = { name: 'Parent', children: [{ name: 'Child' }] };
// Standard React usage
import Component from 'package';
<Component data={data} onEvent={handler} />;
// State management pattern
const [treeData, setTreeData] = useState(initialData);
const onToggle = (node) => { /* update state */ };
| Feature | react-d3-tree | react-treebeard |
|---|---|---|
| Rendering | πΌοΈ SVG (D3.js) | π§± DOM (HTML/CSS) |
| Use Case | π Org Charts, Diagrams | π File Explorers, Menus |
| Navigation | π Zoom & Pan | β¨οΈ Expand, Collapse, Select |
| Customization | π¨ Custom React Components in SVG | π¨ CSS & Decorator Objects |
| Data Root | π³ Single Root Object | π² Array of Root Nodes |
| Accessibility | β οΈ Limited (SVG focus) | β Better (DOM focus) |
react-d3-tree is like a digital whiteboard ποΈβperfect for visualizing relationships, hierarchies, and structures where the layout itself conveys meaning. Use it for dashboards, org charts, and network diagrams.
react-treebeard is like a filing cabinet ποΈβperfect for navigating large datasets where the user needs to find, select, and manage specific items. Use it for settings panels, file pickers, and permission trees.
Final Thought: The choice isn't just about features; it's about the mental model of your users. Do they need to see the structure (choose react-d3-tree), or do they need to navigate the structure (choose react-treebeard)? Always check the maintenance status of react-treebeard before committing, as community forks may offer better long-term stability.
Choose react-d3-tree if you need to visualize hierarchical data as a diagram, such as an organizational chart, family tree, or decision tree. It is ideal when you require SVG-based rendering for high-quality scaling, custom node shapes, or radial tree layouts. Avoid this package if you need a standard file-explorer UI with complex checkbox logic or deep DOM integration.
Choose react-treebeard if you are building a file explorer, settings menu, or any UI that requires a traditional collapsible tree view with checkboxes and keyboard navigation. It is better suited for DOM-based rendering where CSS styling and standard HTML interaction patterns are preferred over SVG diagrams. Note that you should verify its current maintenance status before committing, as it has historically had periods of inactivity.
React D3 Tree is a React component that lets you represent hierarchical data (e.g. family trees, org charts, file directories) as an interactive tree graph with minimal setup, by leveraging D3's tree layout.
Upgrading from v1? Check out the v2 release notes.
npm i --save react-d3-tree
import React from 'react';
import Tree from 'react-d3-tree';
// This is a simplified example of an org chart with a depth of 2.
// Note how deeper levels are defined recursively via the `children` property.
const orgChart = {
name: 'CEO',
children: [
{
name: 'Manager',
attributes: {
department: 'Production',
},
children: [
{
name: 'Foreman',
attributes: {
department: 'Fabrication',
},
children: [
{
name: 'Worker',
},
],
},
{
name: 'Foreman',
attributes: {
department: 'Assembly',
},
children: [
{
name: 'Worker',
},
],
},
],
},
],
};
export default function OrgChartTree() {
return (
// `<Tree />` will fill width/height of its container; in this case `#treeWrapper`.
<div id="treeWrapper" style={{ width: '50em', height: '20em' }}>
<Tree data={orgChart} />
</div>
);
}
For details on all props accepted by Tree, check out the TreeProps reference docs.
The only required prop is data, all other props on Tree are optional/pre-defined (see "Default value" on each prop definition).
react-d3-tree provides default implementations for Tree's nodes & links, which are intended to get you up & running with a working tree quickly.
This section is focused on explaining how to provide data, styles and event handlers for the default Tree implementation.
Need more fine-grained control over how nodes & links appear/behave? Check out the Customizing the Tree section below.
dataBy default, Tree expects each node object in data to implement the RawNodeDatum interface:
interface RawNodeDatum {
name: string;
attributes?: Record<string, string | number | boolean>;
children?: RawNodeDatum[];
}
The orgChart example in the Usage section above is an example of this:
name. This is rendered as the node's primary label.attributes defined (the CEO node does not). The key-value pairs in attributes are rendered as a list of secondary labels.RawNodeDatum objects nested inside them via the children key, creating a hierarchy from which the tree graph can be generated.Tree provides the following props to style different types of nodes, all of which use an SVG circle by default:
rootNodeClassName - applied to the root node.branchNodeClassName - applied to any node with 1+ children.leafNodeClassName - applied to any node without children.To visually distinguish these three types of nodes from each other by color, we could provide each with their own class:
/* custom-tree.css */
.node__root > circle {
fill: red;
}
.node__branch > circle {
fill: yellow;
}
.node__leaf > circle {
fill: green;
/* Let's also make the radius of leaf nodes larger */
r: 40;
}
import React from 'react';
import Tree from 'react-d3-tree';
import './custom-tree.css';
// ...
export default function StyledNodesTree() {
return (
<div id="treeWrapper" style={{ width: '50em', height: '20em' }}>
<Tree
data={data}
rootNodeClassName="node__root"
branchNodeClassName="node__branch"
leafNodeClassName="node__leaf"
/>
</div>
);
}
For more details on the
classNameprops for nodes, see the TreeProps reference docs.
Tree provides the pathClassFunc property to pass additional classNames to every link to be rendered.
Each link calls pathClassFunc with its own TreeLinkDatum and the tree's current orientation. Tree expects pathClassFunc to return a className string.
function StyledLinksTree() {
const getDynamicPathClass = ({ source, target }, orientation) => {
if (!target.children) {
// Target node has no children -> this link leads to a leaf node.
return 'link__to-leaf';
}
// Style it as a link connecting two branch nodes by default.
return 'link__to-branch';
};
return (
<Tree
data={data}
// Statically apply same className(s) to all links
pathClassFunc={() => 'custom-link'}
// Want to apply multiple static classes? `Array.join` is your friend :)
pathClassFunc={() => ['custom-link', 'extra-custom-link'].join(' ')}
// Dynamically determine which `className` to pass based on the link's properties.
pathClassFunc={getDynamicPathClass}
/>
);
}
For more details, see the
PathClassFunctionreference docs.
Tree exposes the following event handler callbacks by default:
Note: Nodes are expanded/collapsed whenever
onNodeClickfires. To prevent this, set thecollapsibleprop tofalse.
onNodeClickwill still fire, but it will not change the target node's expanded/collapsed state.
renderCustomNodeElementThe renderCustomNodeElement prop accepts a custom render function that will be used for every node in the tree.
Cases where you may find rendering your own Node element useful include:
<circle>) - Example (codesandbox.io)foreignObject tag to render HTML inside the SVG namespace - Example (codesandbox.io)pathFuncThe pathFunc prop accepts a predefined PathFunctionOption enum or a user-defined PathFunction.
By changing or providing your own pathFunc, you are able to change how links between nodes of the tree (which are SVG path tags under the hood) are drawn.
The currently available enums are:
diagonal (default)elbowstraightstepWant to see how each option looks? Try them out on the playground.
pathFuncIf none of the available path functions suit your needs, you're also able to provide a custom PathFunction:
function CustomPathFuncTree() {
const straightPathFunc = (linkDatum, orientation) => {
const { source, target } = linkDatum;
return orientation === 'horizontal'
? `M${source.y},${source.x}L${target.y},${target.x}`
: `M${source.x},${source.y}L${target.x},${target.y}`;
};
return (
<Tree
data={data}
// Passing `straight` function as a custom `PathFunction`.
pathFunc={straightPathFunc}
/>
);
}
For more details, see the
PathFunctionreference docs.
To set up react-d3-tree for local development, clone the repo and follow the steps below:
# 1. Set up the library, create a reference to it for symlinking.
cd react-d3-tree
npm i
npm link
# 2. Set up the demo/playground, symlink to the local copy of `react-d3-tree`.
cd demo
npm i
npm link react-d3-tree
Tip: If you'd prefer to use your own app for development instead of the demo, simply run
npm link react-d3-treein your app's root folder instead of the demo's :)
npm run build:watch
If you're using react-d3-tree/demo for development, open up another terminal window in the demo directory and call:
npm start
A huge thank you to all the contributors, as well as users who have opened issues with thoughtful suggestions and feedback.