Work Breakdown Structure (WBS) in React Gantt component

19 Nov 202524 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 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/31.2.12/material.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>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</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/31.2.12/material.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>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='root'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>

Limitations

The WBS feature has a few limitations in the Gantt 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.