Hierarchical Tree Layout in React Diagram

21 Aug 202620 minutes to read

The hierarchical tree layout arranges nodes in a clear parent-child structure. It is suitable for organizational charts, directory structures, and similar hierarchies. The relationship between nodes is defined through connectors or data source fields such as parentId, so an explicit root node is not required.

Hierarchical Tree Layout Output:

Hierarchical tree layout showing nodes arranged in a single parent-child hierarchy

Hierarchical Tree Layout with Nodes and Connectors

To arrange nodes in a hierarchical structure, specify the layout type as HierarchicalTree. This approach provides full control over node and connector definitions while leveraging automatic positioning.

NOTE

Before proceeding, ensure that the @syncfusion/ej2-react-diagrams package is installed and that the DiagramComponent, Inject (from @syncfusion/ej2-react-diagrams), and the required layout modules are imported in your project.

NOTE

The HierarchicalTree module must be injected into the diagram using the Inject component, for example: <Inject services={[HierarchicalTree]} />. Without this injection, the hierarchical tree layout will not be applied.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, DataBinding, HierarchicalTree } from "@syncfusion/ej2-react-diagrams";

//Uses layout to auto-arrange nodes on the diagram page
let layout = {
    //Sets layout type
    type: 'HierarchicalTree'
};

//Initialize nodes for diagram
let nodes = [
    {
        id: 'Steve-Ceo',
    },
    {
        id: 'Kevin-Manager',
    },
    {
        id: 'Peter-Manager',
    },
    {
        id: 'John-Manager',
    },
    {
        id: 'Mary-CSE',
    },
    {
        id: 'Jim-CSE',
    },
    {
        id: 'Martin-CSE',
    },
];

//Initialize connectors for diagram
let connectors = [
    {
        id: 'Steve-Ceo_Kevin-Manager',
        sourceID: 'Steve-Ceo',
        targetID: 'Kevin-Manager',
    },
    {
        id: 'Steve-Ceo_Peter-Manager',
        sourceID: 'Steve-Ceo',
        targetID: 'Peter-Manager',
    },
    {
        id: 'Peter-Manager_John-Manager',
        sourceID: 'Peter-Manager',
        targetID: 'John-Manager',
    },
    {
        id: 'Peter-Manager_Mary-CSE',
        sourceID: 'Peter-Manager',
        targetID: 'Mary-CSE',
    },
    {
        id: 'Kevin-Manager_Jim-CSE',
        sourceID: 'Kevin-Manager',
        targetID: 'Jim-CSE',
    },
    {
        id: 'Kevin-Manager_Martin-CSE',
        sourceID: 'Kevin-Manager',
        targetID: 'Martin-CSE',
    },
];

export default function App() {

    return (
        <div>
            <DiagramComponent
                id="container"
                width={"100%"}
                height={"550px"}
                nodes={nodes}
                connectors={connectors}
                //Uses layout to auto-arrange nodes on the diagram page
                layout={layout}

                //Sets the default properties for nodes
                getNodeDefaults={(node) => {
                    node.annotations = [{ content: node.id }];
                    node.width = 100; node.height = 40;
                    return node;
                }}

                //Sets the default properties for connectors
                getConnectorDefaults={(connector) => {
                    connector.type = 'Orthogonal';
                    return connector;
                }}
            >

                {/* Inject necessary services for the diagram */}
                <Inject services={[DataBinding, HierarchicalTree]} />
            </DiagramComponent>
        </div>
    );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, ConnectorModel, DataBinding,
  NodeModel, HierarchicalTree, LayoutModel } from "@syncfusion/ej2-react-diagrams";

//Uses layout to auto-arrange nodes on the diagram page
let layout: LayoutModel = {
  //Sets layout type
  type: 'HierarchicalTree'
};

//Initialize nodes for diagram
let nodes: NodeModel[] = [
  {
    id: 'Steve-Ceo',
  },
  {
    id: 'Kevin-Manager',
  },
  {
    id: 'Peter-Manager',
  },
  {
    id: 'John-Manager',
  },
  {
    id: 'Mary-CSE',
  },
  {
    id: 'Jim-CSE',
  },
  {
    id: 'Martin-CSE',
  },
];

//Initialize connectors for diagram
let connectors: ConnectorModel[] = [
  {
    id: 'Steve-Ceo_Kevin-Manager',
    sourceID: 'Steve-Ceo',
    targetID: 'Kevin-Manager',
  },
  {
    id: 'Steve-Ceo_Peter-Manager',
    sourceID: 'Steve-Ceo',
    targetID: 'Peter-Manager',
  },
  {
    id: 'Peter-Manager_John-Manager',
    sourceID: 'Peter-Manager',
    targetID: 'John-Manager',
  },
  {
    id: 'Peter-Manager_Mary-CSE',
    sourceID: 'Peter-Manager',
    targetID: 'Mary-CSE',
  },
  {
    id: 'Kevin-Manager_Jim-CSE',
    sourceID: 'Kevin-Manager',
    targetID: 'Jim-CSE',
  },
  {
    id: 'Kevin-Manager_Martin-CSE',
    sourceID: 'Kevin-Manager',
    targetID: 'Martin-CSE',
  },
];

export default function App() {

  return (
    <div>
      <DiagramComponent
        id="container"
        width={"100%"}
        height={"550px"}
        nodes={nodes}
        connectors={connectors}
        //Uses layout to auto-arrange nodes on the diagram page
        layout={layout}

        //Sets the default properties for nodes
        getNodeDefaults={(node: NodeModel) => {
          node.annotations = [{ content: node.id }];
          node.width = 100; node.height = 40;
          return node;
        }}

        //Sets the default properties for connectors
        getConnectorDefaults={(connector: ConnectorModel) => {
          connector.type = 'Orthogonal';
          return connector;
        }}
      >

        {/* Inject necessary services for the diagram */}
        <Inject services={[DataBinding, HierarchicalTree]} />
      </DiagramComponent>
    </div>

  );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);

Hierarchical Layout with DataSource

For data-driven scenarios, hierarchical layout can be created using a DataSource, which automatically generates nodes and connectors based on the data relationships. This approach reduces the need to define each node and connector manually, making it well suited for larger datasets that may change over time.

NOTE

When using a DataSource, configure dataSourceSettings with the id and parentId fields so the layout can resolve parent-child relationships. Without these fields, the generated nodes cannot be linked into a hierarchical structure.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, DataBinding, HierarchicalTree } from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";

//Uses layout to auto-arrange nodes on the diagram page
let layout = {
    //Sets layout type
    type: 'HierarchicalTree'
};

//Initializes data source
let data = [
    { Name: "Steve-Ceo" },
    { Name: "Kevin-Manager", ReportingPerson: "Steve-Ceo" },
    { Name: "Peter-Manager", ReportingPerson: "Steve-Ceo" },
    { Name: "John- Manager", ReportingPerson: "Peter-Manager" },
    { Name: "Mary-CSE ", ReportingPerson: "Peter-Manager" },
    { Name: "Jim-CSE ", ReportingPerson: "Kevin-Manager" },
    { Name: "Martin-CSE", ReportingPerson: "Kevin-Manager" }
];

let items = new DataManager(data, new Query().take(7));

//Configures data source for diagram
let dataSourceSettings = {
    id: 'Name',
    parentId: 'ReportingPerson',
    dataSource: items
};

export default function App() {

    return (
        <div>
            <DiagramComponent
                id="container"
                width={"100%"}
                height={"550px"}

                //Uses layout to auto-arrange nodes on the diagram page
                layout={layout}

                //Configures data source for diagram
                dataSourceSettings={dataSourceSettings}

                //Sets the default properties for nodes
                getNodeDefaults={(node) => {
                    node.annotations = [{ content: node.data.Name }];
                    node.width = 100; node.height = 40;
                    return node;
                }}

                //Sets the default properties for connectors
                getConnectorDefaults={(connector) => {
                    connector.type = 'Orthogonal';
                    return connector;
                }}
            >

                {/* Inject necessary services for the diagram */}
                <Inject services={[DataBinding, HierarchicalTree]} />
            </DiagramComponent>
        </div>

    );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram"));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DiagramComponent, Inject, ConnectorModel, DataBinding, NodeModel, HierarchicalTree, LayoutModel, DataSourceModel } from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";

//Initializes data source
let data: object[] = [
  { Name: "Steve-Ceo" },
  { Name: "Kevin-Manager", ReportingPerson: "Steve-Ceo" },
  { Name: "Peter-Manager", ReportingPerson: "Steve-Ceo" },
  { Name: "John- Manager", ReportingPerson: "Peter-Manager" },
  { Name: "Mary-CSE ", ReportingPerson: "Peter-Manager" },
  { Name: "Jim-CSE ", ReportingPerson: "Kevin-Manager" },
  { Name: "Martin-CSE", ReportingPerson: "Kevin-Manager" }
];

let items: DataManager = new DataManager(data as JSON[], new Query().take(7));

//Uses layout to auto-arrange nodes on the diagram page
let layout: LayoutModel = {
  //Sets layout type
  type: 'HierarchicalTree'
};

//Configures data source for diagram
let dataSourceSettings: DataSourceModel = {
  id: 'Name',
  parentId: 'ReportingPerson',
  dataSource: items
};

export default function App() {

  return (
    <div>
      <DiagramComponent
        id="container"
        width={"100%"}
        height={"550px"}

        //Uses layout to auto-arrange nodes on the diagram page
        layout={layout}

        //Configures data source for diagram
        dataSourceSettings={dataSourceSettings}

        //Sets the default properties for nodes
        getNodeDefaults={(node: NodeModel) => {
          node.annotations = [{ content: (node.data as { Name: 'string' }).Name }];
          node.width = 100; node.height = 40;
          return node;
        }}

        //Sets the default properties for connectors
        getConnectorDefaults={(connector: ConnectorModel) => {
          connector.type = 'Orthogonal';
          return connector;
        }}
      >

        {/* Inject necessary services for the diagram */}
        <Inject services={[DataBinding, HierarchicalTree]} />
      </DiagramComponent>
    </div>

  );
}

// Render the App component into the 'diagram' element in the DOM
const root = ReactDOM.createRoot(document.getElementById("diagram") as HTMLElement);
root.render(<App />);

NOTE

When using DataSource for layout generation, both DataBinding and HierarchicalTree modules must be injected into the diagram.

Troubleshooting

If the hierarchical tree layout does not render as expected, check the following common pitfalls:

  • Nodes are not arranged hierarchically or appear overlapping: Verify that the HierarchicalTree module is injected via Inject and layout.type is set to "HierarchicalTree".
  • Diagram appears blank when using DataSource: Ensure that dataSourceSettings is configured with valid id and parentId values so the layout can resolve parent-child relationships.
  • Data-driven nodes are not generated: Confirm that the DataBinding module is injected in addition to HierarchicalTree when using a DataSource.
  • Connectors are missing between nodes: Check that connectors are defined (or that parentId values resolve correctly in the data source) so the layout can link related nodes.