Work Breakdown Structure (WBS) in React Gantt Chart

6 Aug 202624 minutes to read

The Work Breakdown Structure (WBS) organizes project tasks hierarchically by assigning unique codes to each task. This improves task visibility and management, especially in large-scale construction or enterprise-level software projects.

Configuration and implementation

To enable WBS in the Gantt Chart component:

  • Enable WBS Codes: Set enableWBS to true to automatically generate unique task codes and define their predecessors.
  • Auto-Update Codes: Set enableAutoWbsUpdate to true to maintain accurate WBS codes during operations such as sorting, editing, or drag-and-drop.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Selection, ColumnsDirective, ColumnDirective, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu, EventMarkersDirective, EventMarkerDirective } from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
    const taskFields = {
        id: "TaskID",
        name: "TaskName",
        startDate: "StartDate",
        endDate: "EndDate",
        duration: "Duration",
        progress: "Progress",
        dependency: "Predecessor",
        parentID: 'ParentID'
    };

    let ganttInstance;
    const eventMarkerDay1 = new Date('04/02/2024');
    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true,
    };

    const toolbar = ["Add", "Edit", "Update", "Delete", "Cancel", "ExpandAll", "CollapseAll"];

    const timelineSettings = {
        showTooltip: true,
        topTier: {
            unit: "Week",
            format: "dd/MM/yyyy",
        },
        bottomTier: {
            unit: "Day",
            count: 1,
        },
    };

    const labelSettings = {
        taskLabel: '${Progress}%'
    };

    const projectStartDate = new Date("03/31/2024");
    const projectEndDate = new Date("05/30/2024");

    const splitterSettings = {
        columnIndex: 4
    };

    const selectionSettings = {
        mode: "Row",
        type: "Single",
        enableToggle: false,
    };

    const tooltipSettings = {
        showTooltip: true,
    };

    const filterSettings = {
        type: "Menu",
    };

    return <GanttComponent id="EnableWbs" taskFields={taskFields} ref={ganttInstance} toolbar={toolbar} treeColumnIndex={2} dataSource={WBSData} allowSorting={true} enableContextMenu={true} enableWBS={true} enableAutoWbsUpdate={true} editSettings={editSettings} allowSelection={true} allowPdfExport={true} splitterSettings={splitterSettings} selectionSettings={selectionSettings} tooltipSettings={tooltipSettings} filterSettings={filterSettings} timelineSettings={timelineSettings} highlightWeekends={true} allowFiltering={true} gridLines={"Both"} labelSettings={labelSettings} taskbarHeight={20} rowHeight={40} height={"550px"} allowUnscheduledTasks={true} projectStartDate={projectStartDate} projectEndDate={projectEndDate}>
        <ColumnsDirective>
            <ColumnDirective field="TaskID" visible={false} />
            <ColumnDirective field="WBSCode" width='150px' />
            <ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width='260px' />
            <ColumnDirective field="StartDate" headerText="Start Date" width='140px' />
            <ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width='190px' />
            <ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width='130px' />
            <ColumnDirective field="Progress" headerText="Progress" />
        </ColumnsDirective>
        <EventMarkersDirective>
            <EventMarkerDirective day={eventMarkerDay1} label='Project Initiation'></EventMarkerDirective>
        </EventMarkersDirective>
        <Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu]} />
    </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Selection, ColumnsDirective, ColumnDirective, Toolbar, DayMarkers, Edit, Filter, Sort, ContextMenu, EventMarkersDirective, EventMarkerDirective } from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';
function App() {
    const taskFields = {
        id: "TaskID",
        name: "TaskName",
        startDate: "StartDate",
        endDate: "EndDate",
        duration: "Duration",
        progress: "Progress",
        dependency: "Predecessor",
        parentID: 'ParentID'
    };

    let ganttInstance;
    const eventMarkerDay1 = new Date('04/02/2024');
    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true,
    };

    const toolbar = ["Add", "Edit", "Update", "Delete", "Cancel", "ExpandAll", "CollapseAll"];

    const timelineSettings = {
        showTooltip: true,
        topTier: {
            unit: "Week",
            format: "dd/MM/yyyy",
        },
        bottomTier: {
            unit: "Day",
            count: 1,
        },
    };

    const labelSettings = {
        taskLabel: '${Progress}%'
    };

    const projectStartDate = new Date("03/31/2024");
    const projectEndDate = new Date("05/30/2024");

    const splitterSettings = {
        columnIndex: 4
    };

    const selectionSettings = {
        mode: "Row",
        type: "Single",
        enableToggle: false,
    };

    const tooltipSettings = {
        showTooltip: true,
    };

    const filterSettings = {
        type: "Menu",
    };

    return <GanttComponent id="EnableWbs" taskFields={taskFields} ref={ganttInstance} toolbar={toolbar} treeColumnIndex={2} dataSource={WBSData} allowSorting={true} enableContextMenu={true} enableWBS={true} enableAutoWbsUpdate={true} editSettings={editSettings} allowSelection={true} allowPdfExport={true} splitterSettings={splitterSettings} selectionSettings={selectionSettings} tooltipSettings={tooltipSettings} filterSettings={filterSettings} timelineSettings={timelineSettings} highlightWeekends={true} allowFiltering={true} gridLines={"Both"} labelSettings={labelSettings} taskbarHeight={20} rowHeight={40} height={"550px"} allowUnscheduledTasks={true} projectStartDate={projectStartDate} projectEndDate={projectEndDate}>
        <ColumnsDirective>
            <ColumnDirective field="TaskID" visible={false} />
            <ColumnDirective field="WBSCode" width='150px' />
            <ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width='260px' />
            <ColumnDirective field="StartDate" headerText="Start Date" width='140px' />
            <ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width='190px' />
            <ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width='130px' />
            <ColumnDirective field="Progress" headerText="Progress" />
        </ColumnsDirective>
        <EventMarkersDirective>
            <EventMarkerDirective day={eventMarkerDay1} label='Project Initiation'></EventMarkerDirective>
        </EventMarkersDirective>
        <Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu]} />
    </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.2.2/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>

Managing WBS code updates

To optimize performance, WBS code updates can be controlled using the actionBegin and dataBound events. This is especially useful during operations like row drag-and-drop, where auto-update is triggered only during that specific action to ensure efficient and accurate code handling.

In the following example, WBS auto-update is enabled only during the row drag and drop action using these events.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Selection,
    ColumnsDirective,
    ColumnDirective,
    Toolbar,
    DayMarkers,
    Edit,
    Filter,
    Sort,
    ContextMenu,
    EventMarkersDirective,
    EventMarkerDirective,
    RowDD
} from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';

function App() {
    let ganttInstance;
    let isRowDropped = false;

    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        dependency: 'Predecessor',
        parentID: 'ParentID'
    };

    const eventMarkerDay1 = new Date('04/02/2024');

    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true
    };

    const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];

    const timelineSettings = {
        showTooltip: true,
        topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
        bottomTier: { unit: 'Day', count: 1 }
    };

    const labelSettings = { taskLabel: '${Progress}%' };

    const projectStartDate = new Date('03/31/2024');
    const projectEndDate = new Date('05/30/2024');

    const splitterSettings = { columnIndex: 4 };
    const selectionSettings = { mode: 'Row', type: 'Single', enableToggle: false };
    const tooltipSettings = { showTooltip: true };
    const filterSettings = { type: 'Menu' };

    const dataBound = () => {
        if (isRowDropped && ganttInstance) {
            ganttInstance.enableAutoWbsUpdate = false;
            isRowDropped = false;
        }
    };

    const actionBegin = (args) => {
        if (args.requestType === 'beforeDrop' && ganttInstance) {
            isRowDropped = true;
            ganttInstance.enableAutoWbsUpdate = true;
        }
    };

    return (
        <GanttComponent
            id="EnableWbs"
            ref={(gantt) => (ganttInstance = gantt)}
            taskFields={taskFields}
            toolbar={toolbar}
            treeColumnIndex={2}
            dataSource={WBSData}
            allowSorting={true}
            enableContextMenu={true}
            enableWBS={true}
            enableAutoWbsUpdate={true}
            editSettings={editSettings}
            allowSelection={true}
            allowPdfExport={true}
            splitterSettings={splitterSettings}
            selectionSettings={selectionSettings}
            tooltipSettings={tooltipSettings}
            filterSettings={filterSettings}
            timelineSettings={timelineSettings}
            highlightWeekends={true}
            allowFiltering={true}
            gridLines="Both"
            labelSettings={labelSettings}
            taskbarHeight={20}
            rowHeight={40}
            height="550px"
            allowUnscheduledTasks={true}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            allowRowDragAndDrop={true}
            dataBound={dataBound}
            actionBegin={actionBegin}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" visible={false} />
                <ColumnDirective field="WBSCode" width="150px" />
                <ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width="260px" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="140px" />
                <ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width="190px" />
                <ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width="130px" />
                <ColumnDirective field="Progress" headerText="Progress" />
            </ColumnsDirective>
            <EventMarkersDirective>
                <EventMarkerDirective day={eventMarkerDay1} label="Project Initiation" />
            </EventMarkersDirective>
            <Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu, RowDD]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    Inject,
    Selection,
    ColumnsDirective,
    ColumnDirective,
    Toolbar,
    DayMarkers,
    Edit,
    Filter,
    Sort,
    ContextMenu,
    EventMarkersDirective,
    EventMarkerDirective,
    actionBeginEventArgs,
    RowDD
} from '@syncfusion/ej2-react-gantt';
import { WBSData } from './datasource';

function App() {
    let ganttInstance: GanttComponent;
    let isRowDropped = false;

    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        dependency: 'Predecessor',
        parentID: 'ParentID'
    };

    const eventMarkerDay1 = new Date('04/02/2024');

    const editSettings = {
        allowAdding: true,
        allowEditing: true,
        allowDeleting: true,
        allowTaskbarEditing: true,
        showDeleteConfirmDialog: true
    };

    const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];

    const timelineSettings = {
        showTooltip: true,
        topTier: { unit: 'Week', format: 'dd/MM/yyyy' },
        bottomTier: { unit: 'Day', count: 1 }
    };

    const labelSettings = { taskLabel: '${Progress}%' };

    const projectStartDate = new Date('03/31/2024');
    const projectEndDate = new Date('05/30/2024');

    const splitterSettings = { columnIndex: 4 };
    const selectionSettings = { mode: 'Row', type: 'Single', enableToggle: false };
    const tooltipSettings = { showTooltip: true };
    const filterSettings = { type: 'Menu' };

    const dataBound = () => {
        if (isRowDropped && ganttInstance) {
            ganttInstance.enableAutoWbsUpdate = false;
            isRowDropped = false;
        }
    };

    const actionBegin = (args: actionBeginEventArgs) => {
        if (args.requestType === 'beforeDrop' && ganttInstance) {
            isRowDropped = true;
            ganttInstance.enableAutoWbsUpdate = true;
        }
    };

    return (
        <GanttComponent
            id="EnableWbs"
            ref={(gantt) => (ganttInstance = gantt)}
            taskFields={taskFields}
            toolbar={toolbar}
            treeColumnIndex={2}
            dataSource={WBSData}
            allowSorting={true}
            enableContextMenu={true}
            enableWBS={true}
            enableAutoWbsUpdate={true}
            editSettings={editSettings}
            allowSelection={true}
            allowPdfExport={true}
            splitterSettings={splitterSettings}
            selectionSettings={selectionSettings}
            tooltipSettings={tooltipSettings}
            filterSettings={filterSettings}
            timelineSettings={timelineSettings}
            highlightWeekends={true}
            allowFiltering={true}
            gridLines="Both"
            labelSettings={labelSettings}
            taskbarHeight={20}
            rowHeight={40}
            height="550px"
            allowUnscheduledTasks={true}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            allowRowDragAndDrop={true}
            dataBound={dataBound}
            actionBegin={actionBegin}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" visible={false} />
                <ColumnDirective field="WBSCode" width="150px" />
                <ColumnDirective field="TaskName" headerText="Task Name" allowReordering={false} width="260px" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="140px" />
                <ColumnDirective field="WBSPredecessor" headerText="WBS Predecessor" width="190px" />
                <ColumnDirective field="Duration" headerText="Duration" allowEditing={false} width="130px" />
                <ColumnDirective field="Progress" headerText="Progress" />
            </ColumnsDirective>
            <EventMarkersDirective>
                <EventMarkerDirective day={eventMarkerDay1} label="Project Initiation" />
            </EventMarkersDirective>
            <Inject services={[Selection, DayMarkers, Toolbar, Edit, Filter, Sort, ContextMenu, RowDD]} />
        </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.2.2/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>

Limitations

The WBS feature has a few limitations in the Gantt Chart component:

  • Editing of the WBS code and WBS predecessor columns is not supported.
  • Load on demand is not supported with the WBS feature.
  • WBS Code and WBS Predecessor fields cannot be mapped directly from the data source.