Expand and Collapse Nodes in React Diagram Component
21 Oct 202524 minutes to read
The React Diagram component provides built-in support for expanding and collapsing nodes, enabling users to create hierarchical views where child nodes can be hidden or shown dynamically. This functionality is particularly useful for organizational charts, mind maps, and tree structures where managing visual complexity is essential.
The expand and collapse feature allows users to:
- Compress hierarchical views to show only root elements.
- Toggle visibility of child nodes interactively.
- Customize the appearance of expand and collapse icons.
- Control the initial state of nodes programmatically.
The following properties control the expand and collapse behavior of nodes:
- expandIcon - Defines the icon displayed when a node can be expanded.
- collapseIcon - Defines the icon displayed when a node can be collapsed.
NOTE
Icons are only created when the node has outgoing edges (outEdges).
For detailed API information, refer toexpandIcon and collapseIcon.
Customizing expand and collapse icons
Size and shape configuration
Define the size of icons using the width and height properties.
The shape property of expandIcon and collapseIcon allows customization of the icon appearance.
The following code example demonstrates how to create icons with various shapes:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
DiagramComponent,
Inject,
HierarchicalTree,
DataBinding,
} from '@syncfusion/ej2-react-diagrams';
import { DataManager, Query } from '@syncfusion/ej2-data';
//Initializes data source
let data = [
{
Name: 'Node 1',
},
{
Name: 'Node 2',
ReportingPerson: 'Node 1',
},
];
let items = new DataManager(data, new Query().take(7));
function App() {
return (
<div className="control-pane">
<div className="control-section">
<div className="content-wrapper" style={{ width: '100%' }}>
<DiagramComponent
id="container"
width={'100%'}
height={'550px'}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'HierarchicalTree',
}}
//Configures data source for diagram
dataSourceSettings={{
id: 'Name',
parentId: 'ReportingPerson',
dataManager: items,
}}
//Sets the default properties for nodes
getNodeDefaults={(obj) => {
obj.shape = {
type: 'Text',
content: obj.data.Name,
};
obj.style = {
fill: 'None',
strokeColor: 'none',
strokeWidth: 2,
bold: true,
color: 'white',
};
obj.borderColor = 'white';
obj.width = 100;
obj.height = 40;
obj.backgroundColor = '#6BA5D7';
obj.borderWidth = 1;
obj.shape.margin = {
left: 5,
right: 5,
top: 5,
bottom: 5,
};
obj.expandIcon = {
height: 10,
width: 10,
shape: 'ArrowDown',
fill: 'lightgray',
offset: { x: 0.5, y: 1 },
};
obj.collapseIcon.offset = { x: 0.5, y: 1 };
obj.collapseIcon.height = 10;
obj.collapseIcon.width = 10;
obj.collapseIcon.shape = 'ArrowUp';
obj.collapseIcon.fill = 'lightgray';
return obj;
}}
>
<Inject services={[DataBinding, HierarchicalTree]} />
</DiagramComponent>
</div>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);import * as React from "react";
import * as ReactDOM from 'react-dom';
import {
DiagramComponent,
Inject,
HierarchicalTree,
DataBinding,
} from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";
//Initializes data source
let data: object[] = [
{
Name: 'Node 1',
},
{
Name: 'Node 2',
ReportingPerson: 'Node 1',
},
];
let items = new DataManager(data, new Query().take(7));
function App() {
return (
<div className="control-pane">
<div className="control-section">
<div className="content-wrapper" style={{ width: '100%' }}>
<DiagramComponent
id="container"
width={'100%'}
height={'550px'}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'HierarchicalTree',
}}
//Configures data source for diagram
dataSourceSettings={{
id: 'Name',
parentId: 'ReportingPerson',
dataManager: items,
}}
//Sets the default properties for nodes
getNodeDefaults={(obj) => {
obj.shape = {
type: 'Text',
content: obj.data.Name,
};
obj.style = {
fill: 'None',
strokeColor: 'none',
strokeWidth: 2,
bold: true,
color: 'white',
};
obj.borderColor = 'white';
obj.width = 100;
obj.height = 40;
obj.backgroundColor = '#6BA5D7';
obj.borderWidth = 1;
obj.shape.margin = {
left: 5,
right: 5,
top: 5,
bottom: 5,
};
obj.expandIcon = {
height: 10,
width: 10,
shape: 'ArrowDown',
fill: 'lightgray',
offset: { x: 0.5, y: 1 },
};
obj.collapseIcon.offset = { x: 0.5, y: 1 };
obj.collapseIcon.height = 10;
obj.collapseIcon.width = 10;
obj.collapseIcon.shape = 'ArrowUp';
obj.collapseIcon.fill = 'lightgray';
return obj;
}}
>
<Inject services={[DataBinding, HierarchicalTree]} />
</DiagramComponent>
</div>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);Styling and appearance
Customize the visual appearance of icons using the following properties:
borderColor, borderWidth, and fill properties.
The corner radius can be set using the cornerRadius property of the icon.
The icon can be aligned relative to the node boundaries. It has margin, offset, horizontalAlignment, and verticalAlignment settings. It is quite tricky, when all four alignments are used together but gives you more control over alignment.
The iconColor property can be used to set the strokeColor of the Icon.
Icons can be precisely positioned relative to node boundaries using margin, offset, horizontalAlignment, and verticalAlignment settings. While combining all four alignment properties provides maximum control, it requires careful consideration of their interactions.
The following code example illustrates the customization of icons.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
DiagramComponent,
Inject,
HierarchicalTree,
DataBinding,
} from '@syncfusion/ej2-react-diagrams';
import { DataManager, Query } from '@syncfusion/ej2-data';
//Initializes data source
let data = [
{
Name: 'Node 1',
},
{
Name: 'Node 2',
ReportingPerson: 'Node 1',
},
];
let items = new DataManager(data, new Query().take(7));
function App() {
return (
<div className="control-pane">
<div className="control-section">
<div className="content-wrapper" style={{ width: '100%' }}>
<DiagramComponent
id="container"
width={'100%'}
height={'550px'}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'HierarchicalTree',
}}
//Configures data source for diagram
dataSourceSettings={{
id: 'Name',
parentId: 'ReportingPerson',
dataManager: items,
}}
//Sets the default properties for nodes
getNodeDefaults={(obj) => {
obj.shape = {
type: 'Text',
content: obj.data.Name,
};
obj.style = {
fill: 'None',
strokeColor: 'none',
strokeWidth: 2,
bold: true,
color: 'white',
};
obj.borderColor = 'white';
obj.width = 100;
obj.height = 40;
obj.backgroundColor = '#6BA5D7';
obj.borderWidth = 1;
obj.shape.margin = {
left: 5,
right: 5,
top: 5,
bottom: 5,
};
obj.expandIcon = {
height: 10,
width: 10,
shape: 'ArrowDown',
fill: 'lightgray',
offset: { x: 0.5, y: 1 },
};
obj.collapseIcon.offset = { x: 0.5, y: 1 };
obj.collapseIcon.height = 10;
obj.collapseIcon.width = 10;
obj.collapseIcon.shape = 'ArrowUp';
obj.collapseIcon.fill = 'lightgray';
return obj;
}}
>
<Inject services={[DataBinding, HierarchicalTree]} />
</DiagramComponent>
</div>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);import * as React from "react";
import * as ReactDOM from 'react-dom';
import {
DiagramComponent,
Inject,
HierarchicalTree,
DataBinding,
} from "@syncfusion/ej2-react-diagrams";
import { DataManager, Query } from "@syncfusion/ej2-data";
//Initializes data source
let data: object[] = [
{
Name: 'Node 1',
},
{
Name: 'Node 2',
ReportingPerson: 'Node 1',
},
];
let items = new DataManager(data, new Query().take(7));
function App() {
return (
<div className="control-pane">
<div className="control-section">
<div className="content-wrapper" style={{ width: '100%' }}>
<DiagramComponent
id="container"
width={'100%'}
height={'550px'}
//Uses layout to auto-arrange nodes on the diagram page
layout={{
//Sets layout type
type: 'HierarchicalTree',
}}
//Configures data source for diagram
dataSourceSettings={{
id: 'Name',
parentId: 'ReportingPerson',
dataManager: items,
}}
//Sets the default properties for nodes
getNodeDefaults={(obj) => {
obj.shape = {
type: 'Text',
content: obj.data.Name,
};
obj.style = {
fill: 'None',
strokeColor: 'none',
strokeWidth: 2,
bold: true,
color: 'white',
};
obj.borderColor = 'white';
obj.width = 100;
obj.height = 40;
obj.backgroundColor = '#6BA5D7';
obj.borderWidth = 1;
obj.shape.margin = {
left: 5,
right: 5,
top: 5,
bottom: 5,
};
obj.expandIcon = {
height: 10,
width: 10,
shape: 'ArrowDown',
fill: 'lightgray',
offset: { x: 0.5, y: 1 },
};
obj.collapseIcon.offset = { x: 0.5, y: 1 };
obj.collapseIcon.height = 10;
obj.collapseIcon.width = 10;
obj.collapseIcon.shape = 'ArrowUp';
obj.collapseIcon.fill = 'lightgray';
return obj;
}}
>
<Inject services={[DataBinding, HierarchicalTree]} />
</DiagramComponent>
</div>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);Managing node expansion state
TheisExpandedproperty controls whether a node displays its child nodes. When set to true, child nodes are visible; when false, they are hidden.
Default value: true
The following example demonstrates how to configure the expansion state of nodes:
let node:NodeModel = {
id: 'Start', width: 140, height: 50, offsetX: 300, offsetY: 50,
//Expand state of node
isExpanded:false
expandIcon: {shape: 'ArrowDown', width: 20,
height: 15},
collapseIcon: {shape: 'ArrowUp', width: 20,
height: 15}
}