Tree Column in React Gantt Chart Component
18 Nov 201824 minutes to read
The React Gantt Chart component provides a structured way to display parent-child relationships using expand/collapse icons.
To configure this, set the treeColumnIndex property to the index of the column where these icons should appear. This enables clear visualization and navigation of hierarchical tasks within the Gantt chart.
<GanttComponent dataSource={data} taskFields={taskSettings} treeColumnIndex={1}>
<!-- Other gantt configurations -->
</GanttComponent>Customize expand and collapse icons
The React Gantt Chart component provides support for customizing default expand/collapse icons through CSS.
To apply custom icons, override the default styles with the following CSS:
.e-gantt .e-grid .e-treegridexpand::before {
content: "\2795";
}
.e-gantt .e-grid .e-treegridcollapse::before {
content: "\2796";
}import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
ColumnsDirective,
ColumnDirective,
} from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings = {
position: '75%'
};
return (
<GanttComponent
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width={90} />
<ColumnDirective field="TaskName" headerText="Task Name" width={290} />
<ColumnDirective field="StartDate" headerText="Start Date" width={120} />
<ColumnDirective field="Duration" headerText="Duration" width={90} />
<ColumnDirective field="Progress" headerText="Progress" width={120} />
</ColumnsDirective>
</GanttComponent>
);
}
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
ColumnsDirective,
ColumnDirective,
SplitterSettingsModel
} from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const taskSettings: object = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings: SplitterSettingsModel = {
position: '75%'
};
return (
<GanttComponent
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width={90} />
<ColumnDirective field="TaskName" headerText="Task Name" width={290} />
<ColumnDirective field="StartDate" headerText="Start Date" width={120} />
<ColumnDirective field="Duration" headerText="Duration" width={90} />
<ColumnDirective field="Progress" headerText="Progress" width={120} />
</ColumnsDirective>
</GanttComponent>
);
}
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
.e-gantt .e-grid .e-treegridexpand::before {
content: "\2795";
}
.e-gantt .e-grid .e-treegridcollapse::before {
content: "\2796";
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Customize indentation of tree column text
The React Gantt Chart component allows customization of the indent space in tree column cells using the queryCellInfo event.
In the following demonstration, indentation is applied by dynamically adding a CSS class to the tree column cell of TaskName using the queryCellInfo event.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
var ganttInstance = null;
var taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
var splitterSettings = {
position: '75%'
};
var queryCellInfo = (args) => {
var rowData = args.data;
var columnIndex = args.column.index;
var treeColumnIndex = ganttInstance.treeColumnIndex;
if (!rowData.hasChildRecords && columnIndex === treeColumnIndex) {
args.cell.classList.add('indents');
}
};
return (
<div>
<GanttComponent
id="gantt"
height="370px"
dataSource={data}
treeColumnIndex={1}
taskFields={taskSettings}
splitterSettings={splitterSettings}
queryCellInfo={queryCellInfo}
ref={g => ganttInstance = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
var ganttInstance: GanttComponent = null;
var taskSettings: object = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
var splitterSettings: object = {
position: '75%'
};
var queryCellInfo = (args: any): void => {
var rowData = args.data;
var columnIndex = args.column.index;
var treeColumnIndex = ganttInstance.treeColumnIndex;
if (!rowData.hasChildRecords && columnIndex === treeColumnIndex) {
args.cell.classList.add('indents');
}
};
return (
<div>
<GanttComponent
id="gantt"
height="370px"
dataSource={data}
treeColumnIndex={1}
taskFields={taskSettings}
splitterSettings={splitterSettings}
queryCellInfo={queryCellInfo}
ref={g => ganttInstance = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
.indents {
text-indent: 80px !important;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Render parent rows in collapsed state
You can collapse all parent rows during initial rendering by setting the collapseAllParentTasks property in the Gantt Chart component.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const gantt = null;
const taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings = {
position: '75%'
};
return (
<div>
<GanttComponent
id="gantt"
height="370px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
collapseAllParentTasks={true}
ref={g => gantt = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const gantt: GanttComponent = null;
const taskSettings: object = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings: object = {
position: '75%'
};
return (
<div>
<GanttComponent
id="gantt"
height="370px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
collapseAllParentTasks={true}
ref={g => gantt = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Retain expand/collapse state on initial load
You can retain the expanded or collapsed state of parent rows during initial rendering by using the expandState property in the data source. This property indicates whether a parent row should be expanded or collapsed when the Gantt Chart component loads.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App () {
const ganttRef = null;
const taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
expandState: 'isExpand',
parentID: 'ParentID'
};
const splitterSettings = {
position: '75%'
};
return (
<div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
ref={g => ganttRef = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App () {
const ganttRef: GanttComponent = null;
const taskSettings: object = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
expandState: 'isExpand',
parentID: 'ParentID'
};
const splitterSettings: object = {
position: '75%'
};
return (
<div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
ref={g => ganttRef = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Persist expand/collapse state across page refresh using localStorage
To retain the expanded and collapsed state of rows after a page refresh in the React Gantt Chart component:
- Use the collapsed event to store the collapsed row’s primary key in
localStoragevia setItem. - On page reload, retrieve the stored keys in the dataBound event using getItem.
- Collapse the corresponding rows using
CollapseByKeyorcollapseRowmethods by passing the saved key or row details.
This approach ensures that row states are preserved across browser sessions, enhancing user experience and continuity.
In the following demo, the steps mentioned above are used to persist the expanded and collapsed state of rows during a browser page refresh.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent, ColumnsDirective, ColumnDirective, Inject, CollapsingEventArgs
} from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const gantt = null;
const collapsingData = [];
const taskSettings = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings = {
position: '75%'
};
// Restore collapsed rows after initial render
const onDataBound = () => {
if (gantt && gantt.treeGrid.initialRender && window.localStorage) {
const storedData = JSON.parse(localStorage.getItem('collapsingData') || '[]');
if (storedData.length) {
storedData.forEach((key) => {
gantt.treeGrid.collapseByKey(key);
});
}
}
};
// Handle collapse event
const onCollapsed = (args) => {
collapsingData.push(args.data.TaskID);
updateLocalStorage(collapsingData);
};
// Handle expand event
const onExpanded = (args) => {
const index = collapsingData.findIndex((id) => id === args.data.TaskID);
if (index !== -1) {
collapsingData.splice(index, 1);
updateLocalStorage(collapsingData);
}
};
const updateLocalStorage = (data) => {
localStorage.setItem('collapsingData', JSON.stringify(data));
};
return (
<div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
dataBound={onDataBound}
collapsed={onCollapsed}
expanded={onExpanded}
ref={g => gantt = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" isPrimaryKey={true} textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent, ColumnsDirective, ColumnDirective, Inject, CollapsingEventArgs
} from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const gantt: GanttComponent = null;
const collapsingData: number[] = [];
const taskSettings: object = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings: object = {
position: '75%'
};
// Restore collapsed rows after initial render
const onDataBound = (): void => {
if (gantt && gantt.treeGrid.initialRender && window.localStorage) {
const storedData = JSON.parse(localStorage.getItem('collapsingData') || '[]');
if (storedData.length) {
storedData.forEach((key: number) => {
gantt.treeGrid.collapseByKey(key);
});
}
}
};
// Handle collapse event
const onCollapsed = (args: CollapsingEventArgs): void => {
collapsingData.push((args.data as any).TaskID);
updateLocalStorage(collapsingData);
};
// Handle expand event
const onExpanded = (args: CollapsingEventArgs): void => {
const index = collapsingData.findIndex((id) => id === (args.data as any).TaskID);
if (index !== -1) {
collapsingData.splice(index, 1);
updateLocalStorage(collapsingData);
}
};
const updateLocalStorage = (data: number[]): void => {
localStorage.setItem('collapsingData', JSON.stringify(data));
};
return (
<div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskSettings}
treeColumnIndex={1}
splitterSettings={splitterSettings}
dataBound={onDataBound}
collapsed={onCollapsed}
expanded={onExpanded}
ref={g => gantt = g}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" isPrimaryKey={true} textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Programmatically expand or collapse rows
The React Gantt Chart component provides built-in methods to programmatically control row expansion and collapse:
- expandAll(): Expands all rows.
gantt.expandAll();- collapseAll(): Collapses all rows.
gantt.collapseAll();-
expandAtLevel(level): Expands rows at a specific level.
gantt.treegrid.expandAtLevel(0);-
collapseAtLevel(level): Collapses rows at a specific level.
gantt.treegrid.collapseAtLevel(0);-
expandByKey(key): Expands a row by primary key.
gantt.treegrid.expandByKey(1); //Here pass the primary key value.-
collapseByKey(key): Collapses a row by primary key.
gantt.treegrid.collapseByKey(1);//Here pass the primary key value.-
expandRow(rowElement): Expands a row using its DOM element.
gantt.treegrid.expandRow(tr); //Here pass the row element as parameter.-
collapseRow(rowElement): Collapses a row using its DOM element.
gantt.treegrid.collapseRow(tr);//Here pass the row element as parameter.import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { data } from './datasource';
function App() {
let gantt = null;
const taskFields = {
id: 'TaskID',
name: 'TaskName',
duration: 'Duration',
progress: 'Progress',
parentID: 'parentID'
};
// 1. Expand all
const expandAll = () => gantt.expandAll();
// 2. Collapse all
const collapseAll = () => gantt.collapseAll();
// 3. Expand at level (Level 0 = root tasks)
const expandLevel0 = () => gantt.treeGrid.expandAtLevel(0);
// 4. Collapse at level (Level 1 = first child level)
const collapseLevel1 = () => gantt.treeGrid.collapseAtLevel(1);
// 5. Expand by key (TaskID)
const expandById = (id) => gantt.treeGrid.expandByKey(id);
// 6. Collapse by key (TaskID)
const collapseById = (id) => gantt.treeGrid.collapseByKey(id);
// 7. Expand first row by DOM element
const expandFirstRow = () => {
const rows = gantt.treeGrid.getRows();
if (rows && rows.length > 0) {
gantt.treeGrid.expandRow(rows[0]);
}
};
// 8. Collapse first row by DOM element
const collapseFirstRow = () => {
const rows = gantt.treeGrid.getRows();
if (rows && rows.length > 0) {
gantt.treeGrid.collapseRow(rows[0]);
}
};
return (
<div>
<div className="controls" style=>
<ButtonComponent cssClass="e-primary" onClick={expandAll}>Expand All</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseAll}>Collapse All</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={expandLevel0}>Expand Level 0</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseLevel1}>Collapse Level 1</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={() => expandById(2)}>Expand Task ID 2</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={() => collapseById(1)}>Collapse Task ID 1</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={expandFirstRow}>Expand First Row (DOM)</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseFirstRow}>Collapse First Row (DOM)</ButtonComponent>
</div>
<GanttComponent
ref={g => gantt = g}
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
height="460px"
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="ID" width="80" />
<ColumnDirective field="TaskName" headerText="Name" width="200" />
<ColumnDirective field="Duration" headerText="Duration" width="100" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { data } from './datasource';
function App() {
let gantt: GanttComponent = null;
const taskFields = {
id: 'TaskID',
name: 'TaskName',
duration: 'Duration',
progress: 'Progress',
parentID: 'parentID'
};
// 1. Expand all
const expandAll = () => gantt.expandAll();
// 2. Collapse all
const collapseAll = () => gantt.collapseAll();
// 3. Expand at level (Level 0 = root tasks)
const expandLevel0 = () => gantt.treeGrid.expandAtLevel(0);
// 4. Collapse at level (Level 1 = first child level)
const collapseLevel1 = () => gantt.treeGrid.collapseAtLevel(1);
// 5. Expand by key (TaskID)
const expandById = (id: number) => gantt.treeGrid.expandByKey(id);
// 6. Collapse by key (TaskID)
const collapseById = (id: number) => gantt.treeGrid.collapseByKey(id);
// 7. Expand first row by DOM element
const expandFirstRow = () => {
const rows = gantt.treeGrid.getRows();
if (rows && rows.length > 0) {
gantt.treeGrid.expandRow(rows[0]);
}
};
// 8. Collapse first row by DOM element
const collapseFirstRow = () => {
const rows = gantt.treeGrid.getRows();
if (rows && rows.length > 0) {
gantt.treeGrid.collapseRow(rows[0]);
}
};
return (
<div>
<div className="controls" style=>
<ButtonComponent cssClass="e-primary" onClick={expandAll}>Expand All</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseAll}>Collapse All</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={expandLevel0}>Expand Level 0</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseLevel1}>Collapse Level 1</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={() => expandById(2)}>Expand Task ID 2</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={() => collapseById(1)}>Collapse Task ID 1</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={expandFirstRow}>Expand First Row (DOM)</ButtonComponent>
<ButtonComponent cssClass="e-primary" onClick={collapseFirstRow}>Collapse First Row (DOM)</ButtonComponent>
</div>
<GanttComponent
ref={g => gantt = g}
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
height="460px"
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="ID" width="80" />
<ColumnDirective field="TaskName" headerText="Name" width="200" />
<ColumnDirective field="Duration" headerText="Duration" width="100" />
</ColumnsDirective>
<Inject services={[]} />
</GanttComponent>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Retrieve expanded records
To retrieve the currently expanded rows in the Gantt Chart component, use the getExpandedRecords method.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
ColumnsDirective,
ColumnDirective,
Inject,
Toolbar
} from '@syncfusion/ej2-react-gantt';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import { ClickEventArgs } from '@syncfusion/ej2-navigations';
import { data } from './datasource';
function App() {
let ganttInstance = null;
let dialogInstance = null;
let parentTasks = [];
var taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
var splitterSettings = { position: '75%' };
var toolbarOptions = [
'Add',
'Edit',
'Delete',
{ text: 'Show Expand Parent Tasks', id: 'show_parents', tooltipText: 'Show expanded parent tasks in dialog' }
];
var onToolbarClick = (args) => {
if (args.item.id === 'show_parents' && ganttInstance && dialogInstance) {
var expandedRecords = ganttInstance.getExpandedRecords(ganttInstance.flatData);
parentTasks = expandedRecords
.filter((record) => record.hasChildRecords && record.expanded === true)
.map((record) => ({
TaskID: record.TaskID,
TaskName: record.TaskName
}));
// Update dialog content manually
var contentHtml = parentTasks.length
? `<ul>${parentTasks.map(task => `<li>Task ID: ${task.TaskID}, Task Name: ${task.TaskName}</li>`).join('')}</ul>`
: `<div>No parent tasks found.</div>`;
dialogInstance.content = contentHtml;
dialogInstance.show();
}
};
return (
<div>
<GanttComponent
ref={(gantt) => (ganttInstance = gantt)}
id="gantt"
height="370px"
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
splitterSettings={splitterSettings}
collapseAllParentTasks={true}
toolbar={toolbarOptions}
toolbarClick={onToolbarClick}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[Toolbar]} />
</GanttComponent>
<DialogComponent
ref={(dialog) => (dialogInstance = dialog)}
width="400px"
height="auto"
header="Parent Tasks"
visible={false}
showCloseIcon={true}
isModal={true}
/>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
GanttComponent,
ColumnsDirective,
ColumnDirective,
Inject,
Toolbar
} from '@syncfusion/ej2-react-gantt';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import { ClickEventArgs } from '@syncfusion/ej2-navigations';
import { data } from './datasource';
function App() {
let ganttInstance: GanttComponent | null = null;
let dialogInstance: DialogComponent | null = null;
let parentTasks: any[] = [];
var taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
var splitterSettings = { position: '75%' };
var toolbarOptions = [
'Add',
'Edit',
'Delete',
{ text: 'Show Expand Parent Tasks', id: 'show_parents', tooltipText: 'Show expanded parent tasks in dialog' }
];
var onToolbarClick = (args: ClickEventArgs): void => {
if (args.item.id === 'show_parents' && ganttInstance && dialogInstance) {
var expandedRecords = ganttInstance.getExpandedRecords(ganttInstance.flatData);
parentTasks = expandedRecords
.filter((record: any) => record.hasChildRecords && record.expanded === true)
.map((record: any) => ({
TaskID: record.TaskID,
TaskName: record.TaskName
}));
// Update dialog content manually
var contentHtml = parentTasks.length
? `<ul>${parentTasks.map(task => `<li>Task ID: ${task.TaskID}, Task Name: ${task.TaskName}</li>`).join('')}</ul>`
: `<div>No parent tasks found.</div>`;
dialogInstance.content = contentHtml;
dialogInstance.show();
}
};
return (
<div>
<GanttComponent
ref={(gantt) => (ganttInstance = gantt)}
id="gantt"
height="370px"
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
splitterSettings={splitterSettings}
collapseAllParentTasks={true}
toolbar={toolbarOptions}
toolbarClick={onToolbarClick}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" width="120" />
<ColumnDirective field="Duration" headerText="Duration" width="90" />
<ColumnDirective field="Progress" headerText="Progress" width="120" />
</ColumnsDirective>
<Inject services={[Toolbar]} />
</GanttComponent>
<DialogComponent
ref={(dialog) => (dialogInstance = dialog)}
width="400px"
height="auto"
header="Parent Tasks"
visible={false}
showCloseIcon={true}
isModal={true}
/>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>Customize expand/collapse behavior using events
You can customize expand and collapse behavior in the React Gantt Chart component using the expanding, expanded, collapsing, and collapsed events. These events allow you to control and respond to row state changes programmatically based on your application logic.
The following sample demonstrates how to customize expand and collapse actions in the React Gantt Chart component:
- Expanding is canceled for the row where TaskID is 1.
- Collapsing is canceled for the row where TaskID is 5.
- When a row is expanded and its Progress is greater than 50, a green background is applied.
- When a row is collapsed and its Progress is less than 50, a red background is applied.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject, Selection } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const taskFields = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
endDate: 'EndDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings = {
position: '75%'
};
let message = '';
let messageColor = 'black';
let msgRef;
const expanding = (args) => {
const data = args.data;
if (data) {
message = `Expanding Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'blue';
if (data.TaskID === 1) {
args.cancel = true;
message = `Expanding cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'red';
}
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
}
};
const collapsing = (args) => {
const data = args.data;
if (data) {
message = `Collapsing Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'orange';
if (data.TaskID === 5) {
args.cancel = true;
message = `Collapsing cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'red';
}
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
}
};
const expanded = (args) => {
const data = args.data;
if (data && args.row) {
message = `Task Expanded: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'green';
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
args.row.style.background = '';
if ((data.Progress) > 50) {
args.row.style.background = '#c0f6c7ff';
}
}
};
const collapsed = (args) => {
const data = args.data;
if (data && args.row) {
message = `Task Collapsed: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'purple';
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
args.row.style.background = '';
if ((data.Progress) < 50) {
args.row.style.background = '#fb9c9cff';
}
}
};
return (
<div className="control-section">
<div style=>
<p ref={(el) => (msgRef = el)} id="message"></p>
</div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
splitterSettings={splitterSettings}
expanding={expanding}
collapsing={collapsing}
expanded={expanded}
collapsed={collapsed}
ref={(gantt) => (ganttRef = gantt)}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[Selection]} />
</GanttComponent>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject, Selection, TaskFieldsModel, SplitterSettingsModel } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
const taskFields: TaskFieldsModel = {
id: 'TaskID',
name: 'TaskName',
startDate: 'StartDate',
endDate: 'EndDate',
duration: 'Duration',
progress: 'Progress',
parentID: 'ParentID'
};
const splitterSettings: SplitterSettingsModel = {
position: '75%'
};
let message: string = '';
let messageColor: string = 'black';
let msgRef: any;
let ganttRef: any;
const expanding = (args: any): void => {
const data = args.data as any;
if (data) {
message = `Expanding Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'blue';
if (data.TaskID === 1) {
args.cancel = true;
message = `Expanding cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'red';
}
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
}
};
const collapsing = (args: any): void => {
const data = args.data as any;
if (data) {
message = `Collapsing Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'orange';
if (data.TaskID === 5) {
args.cancel = true;
message = `Collapsing cancelled for Task: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'red';
}
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
}
};
const expanded = (args: any): void => {
const data = args.data as any;
if (data && args.row) {
message = `Task Expanded: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'green';
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
args.row.style.background = '';
if ((data.Progress) > 50) {
args.row.style.background = '#c0f6c7ff';
}
}
};
const collapsed = (args: any): void => {
const data = args.data as any;
if (data && args.row) {
message = `Task Collapsed: ${data.TaskName} (ID: ${data.TaskID})`;
messageColor = 'purple';
if (msgRef) {
msgRef.innerText = message;
msgRef.style.color = messageColor;
}
args.row.style.background = '';
if ((data.Progress) < 50) {
args.row.style.background = '#fb9c9cff';
}
}
};
return (
<div className="control-section">
<div style=>
<p ref={(el) => (msgRef = el)} id="message"></p>
</div>
<GanttComponent
id="ganttDefault"
height="430px"
dataSource={data}
taskFields={taskFields}
treeColumnIndex={1}
splitterSettings={splitterSettings}
expanding={expanding}
collapsing={collapsing}
expanded={expanded}
collapsed={collapsed}
ref={(gantt) => (ganttRef = gantt)}
>
<ColumnsDirective>
<ColumnDirective field="TaskID" headerText="Task ID" textAlign="Right" width="90" />
<ColumnDirective field="TaskName" headerText="Task Name" textAlign="Left" width="290" />
<ColumnDirective field="StartDate" headerText="Start Date" textAlign="Right" width="120" />
<ColumnDirective field="Duration" headerText="Duration" textAlign="Right" width="90" />
<ColumnDirective field="Progress" headerText="Progress" textAlign="Right" width="120" />
</ColumnsDirective>
<Inject services={[Selection]} />
</GanttComponent>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));<!DOCTYPE html>
<html lang="en">
<head>
<title>Syncfusion React Gantt</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Essential JS 2 for React Components" />
<meta name="author" content="Syncfusion" />
<link href="https://cdn.syncfusion.com/ej2/34.1.29/tailwind3.css" rel="stylesheet" type="text/css" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
<script src="systemjs.config.js"></script>
<style>
#loader {
color: #008cff;
height: 40px;
left: 45%;
position: absolute;
top: 45%;
width: 30%;
}
</style>
</head>
<body>
<div id='root'>
<div id='loader'>Loading....</div>
</div>
</body>
</html>