Skip to content

Latest commit

 

History

751 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React D3 Tree

build status npm package npm package: downloads monthly npm package: minzipped size npm package: types code style: oxfmt

Playground · API reference (v3)

React D3 Tree is a React component that renders hierarchical data, such as family trees, org charts, and file directories, as an interactive tree graph. It uses the tree layout from D3.

Contents

Install

npm install react-d3-tree

React D3 Tree supports React 16, 17, 18, and 19, and ships its own TypeScript types.

Quick start

import React from 'react';
import Tree from 'react-d3-tree';

// Each node has a `name`, optional `attributes`, and optional `children`.
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` fills the width and height of its container.
    <div id="treeWrapper" style={{ width: '50em', height: '20em' }}>
      <Tree data={orgChart} />
    </div>
  );
}

Data format

Tree expects data to be a node object that matches the RawNodeDatum interface:

interface RawNodeDatum {
  name: string;
  attributes?: Record<string, string | number | boolean>;
  children?: RawNodeDatum[];
}
  • name is required. The default node shows it as the node's main label.
  • attributes is optional. The default node lists each key-value pair below the name.
  • children holds the node's child nodes, each of which is also a RawNodeDatum.

data also accepts an array, but Tree renders only its first element.

Props

data is the only required prop. For every prop, its type, and its default value, see the TreeProps reference.

Style nodes

By default, each node is an SVG circle. To style nodes by their position in the tree, pass a class name to one or more of these props:

  • rootNodeClassName: the root node.
  • branchNodeClassName: nodes with children.
  • leafNodeClassName: nodes without children.

For example, to give each kind of node its own color:

/* custom-tree.css */
.node__root > circle {
  fill: red;
}

.node__branch > circle {
  fill: yellow;
}

.node__leaf > circle {
  fill: green;
  /* Leaf nodes also get a larger radius. */
  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>
  );
}

Style links

To add class names to links, pass a function to pathClassFunc. Tree calls it for each link with the link's TreeLinkDatum and the tree's orientation, and adds the returned string to the link's class attribute.

To give every link the same classes, return a fixed string:

<Tree data={data} pathClassFunc={() => 'custom-link extra-custom-link'} />

To pick classes per link, read the link's source and target nodes:

function StyledLinksTree() {
  const getDynamicPathClass = ({ source, target }, orientation) => {
    // The target has no children, so this link leads to a leaf node.
    if (!target.children) {
      return 'link__to-leaf';
    }
    return 'link__to-branch';
  };

  return <Tree data={data} pathClassFunc={getDynamicPathClass} />;
}

Handle events

Tree accepts these event handlers:

A click on a default node's circle expands or collapses the node, then calls onNodeClick. To keep nodes from expanding or collapsing, set collapsible to false; onNodeClick still runs.

To center a node in view when it's clicked, pass the container's size to dimensions.

Render custom nodes

To replace the default node, pass a render function to renderCustomNodeElement. Tree calls it for every node with CustomNodeElementProps and renders the SVG element it returns.

A custom node controls its own clicks. To keep the default behavior, call toggleNode to expand or collapse the node, and onNodeClick to run your onNodeClick handler and, if you set dimensions, center the node.

Example: a different SVG element

This node draws a square instead of a circle and keeps the default click behavior.

const renderRectNode = ({ nodeDatum, toggleNode, onNodeClick }) => (
  <g>
    <rect
      width="20"
      height="20"
      x="-10"
      y="-10"
      onClick={evt => {
        toggleNode();
        onNodeClick(evt);
      }}
    />
    <text x="20">{nodeDatum.name}</text>
  </g>
);

<Tree data={data} renderCustomNodeElement={renderRectNode} />;
Example: custom event handlers

This node splits the click behavior: a click on the label expands or collapses the node, and a click on the circle calls onNodeClick. nodeDatum.__rd3t.collapsed tells you whether the node is collapsed.

const renderLabelToggleNode = ({ nodeDatum, toggleNode, onNodeClick }) => (
  <g>
    <circle r="15" onClick={onNodeClick} />
    <text x="20" onClick={toggleNode}>
      {nodeDatum.name}
      {nodeDatum.children && (nodeDatum.__rd3t.collapsed ? ' (+)' : ' (-)')}
    </text>
  </g>
);

<Tree
  data={data}
  renderCustomNodeElement={renderLabelToggleNode}
  onNodeClick={node => console.log(node.data.name)}
/>;
Example: HTML inside nodes

SVG can't hold HTML elements directly. To render HTML in a node, wrap it in a foreignObject element. If the HTML holds inputs or other controls, set hasInteractiveNodes so that dragging and zooming don't get in their way.

const renderHtmlNode = ({ nodeDatum, toggleNode }) => (
  <g>
    <circle r="15" />
    <foreignObject width="200" height="100" x="20" y="-50">
      <div style={{ border: '1px solid black', backgroundColor: '#dedede' }}>
        <h3 style={{ textAlign: 'center' }}>{nodeDatum.name}</h3>
        {nodeDatum.children && (
          <button type="button" style={{ width: '100%' }} onClick={toggleNode}>
            {nodeDatum.__rd3t.collapsed ? 'Expand' : 'Collapse'}
          </button>
        )}
      </div>
    </foreignObject>
  </g>
);

<Tree data={data} renderCustomNodeElement={renderHtmlNode} hasInteractiveNodes />;

Change how links are drawn

Each link is an SVG path. To change its shape, set pathFunc to one of these options:

  • diagonal (default)
  • elbow
  • straight
  • step

To compare them, try each one in the playground.

For a shape the options don't cover, pass your own PathFunction. Tree calls it for each link with the link's TreeLinkDatum and the tree's orientation, and uses the returned string as the path's d attribute. This example draws straight lines:

function CustomPathFuncTree() {
  const straightPathFunc = ({ source, target }, orientation) =>
    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} pathFunc={straightPathFunc} />;
}

In a horizontal tree, x and y swap: a node's y is its horizontal position.

Contributing

To set up the repo, run the playground, and submit changes, see CONTRIBUTING.md. Thanks to all contributors and to everyone who opens issues with suggestions and feedback.

Older versions

Releases

Packages

Used by

Contributors

Languages