Work Breakdown Structure (WBS) in React Gantt Component

30 Jun 202524 minutes to read

The Work Breakdown Structure (WBS) organizes project tasks hierarchically in the Gantt component by assigning unique codes to each task. This system enhances visualization and management by clearly reflecting task relationships and levels. It is especially useful in complex environments like construction projects or enterprise-scale software development.

Configuration and implementation

To enable and configure WBS in your Gantt component:

  • Enable WBS Codes: Set the enableWBS property to true to automatically generate unique task codes and their predecessors.
  • Auto-Update Codes: Set the enableAutoWbsUpdate property to true to maintain WBS code accuracy during operations like sorting, filtering, 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 { data } from './datasource';
import { useRef } from 'react';

function App() {
    const taskFields = {
        id: "TaskID",
        name: "TaskName",
        startDate: "StartDate",
        endDate: "EndDate",
        duration: "Duration",
        progress: "Progress",
        dependency: "Predecessor",
        parentID: 'ParentId'
    };
    let ganttInstance = useRef(null);
    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 (
        <div>
            <GanttComponent
                id="EnableWbs"
                taskFields={taskFields}
                ref={ganttInstance}
                toolbar={toolbar}
                treeColumnIndex={2}
                dataSource={data}
                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>
        </div>
    );
};
ReactDOM.render(<App />, document.getElementById('root'));
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import { 
  GanttComponent, 
  Inject, 
  Selection, 
  ColumnsDirective, 
  ColumnDirective, 
  Toolbar, 
  DayMarkers, 
  Edit, 
  Filter, 
  Sort, 
  ContextMenu, 
  EventMarkersDirective, 
  EventMarkerDirective 
} 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",
    dependency: "Predecessor",
    parentID: 'ParentId'
  };

  let ganttInstance = useRef(null);
  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 (
    <div>
      <GanttComponent
        id="EnableWbs"
        taskFields={taskFields}
        ref={ganttInstance}
        toolbar={toolbar}
        treeColumnIndex={2}
        dataSource={data}
        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>
    </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/30.2.4/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

For better performance, you can control when WBS codes are updated by using the actionBegin and dataBound events. This is particularly useful during actions like dragging and dropping rows.

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 { data } from './datasource';
import { useRef } from 'react';

function App() {
    const taskFields = {
        id: "TaskID",
        name: "TaskName",
        startDate: "StartDate",
        endDate: "EndDate",
        duration: "Duration",
        progress: "Progress",
        dependency: "Predecessor",
        parentID: 'ParentId'
    };
    let ganttInstance = useRef(null);
    const isRowDropped = useRef(false);
    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 dataBound = () => {
        if (isRowDropped.current) {
            ganttInstance.current.enableAutoWbsUpdate = false;
            isRowDropped.current = false;
        }
    };
    const actionBegin = (args) => {
        if (args.requestType === "rowDropped") {
            isRowDropped.current = true;
            ganttInstance.current.enableAutoWbsUpdate = false;
        }
    };
    const selectionSettings = {
        mode: "Row",
        type: "Single",
        enableToggle: false,
    };
    const tooltipSettings = {
        showTooltip: true,
    };
    const filterSettings = {
        type: "Menu",
    };
    return (
        <div>
            <GanttComponent
                id="EnableWbs"
                taskFields={taskFields}
                ref={ganttInstance}
                toolbar={toolbar}
                treeColumnIndex={2}
                dataSource={data}
                allowSorting={true}
                enableContextMenu={true}
                enableWBS={true}
                allowRowDragAndDrop={true}
                actionBegin={actionBegin.bind(this)}
                dataBound={dataBound.bind(this)}
                enableAutoWbsUpdate={false}
                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, RowDD]} />
            </GanttComponent>
        </div>
    );
};
ReactDOM.render(<App />, document.getElementById('root'));
import React, { useRef } from 'react';
import ReactDOM from 'react-dom';
import { 
  GanttComponent, 
  Inject, 
  Selection, 
  ColumnsDirective, 
  ColumnDirective, 
  Toolbar, 
  DayMarkers, 
  Edit, 
  Filter, 
  Sort, 
  ContextMenu, 
  EventMarkersDirective, 
  EventMarkerDirective 
} 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",
    dependency: "Predecessor",
    parentID: 'ParentId'
  };

  let ganttInstance = useRef(null);
  const isRowDropped = useRef(false);
  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 dataBound = () => {
    if (isRowDropped.current) {
      ganttInstance.current.enableAutoWbsUpdate = false;
      isRowDropped.current = false;
    }
  };

  const actionBegin = (args) => {
    if (args.requestType === "beforeDrop") {
      isRowDropped.current = true;
      ganttInstance.current.enableAutoWbsUpdate = false;
    }
  };

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

  const tooltipSettings = {
    showTooltip: true,
  };

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

  return (
    <div>
      <GanttComponent
        id="EnableWbs"
        taskFields={taskFields}
        ref={ganttInstance}
        toolbar={toolbar}
        treeColumnIndex={2}
        dataSource={data}
        allowSorting={true}
        enableContextMenu={true}
        enableWBS={true}
        dataBound={dataBound.bind(this)}
        actionBegin={actionBegin.bind(this)}
        enableAutoWbsUpdate={false}
        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>
    </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/30.2.4/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 React 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.