HelpBot Assistant

How can I help you?

Scheduling Tasks in React Gantt Chart Component

31 Jan 202624 minutes to read

Task scheduling in the React Gantt Chart component defines and visualizes task start dates, durations, and end dates as taskbars in a project timeline, enabling precise planning and tracking. Configure scheduling with properties like taskFields for mapping task data, taskMode for auto or manual validation, taskType for fixed unit, work, or duration, and durationUnit for day, hour, or minute units. Working time, set via dayWorkingTime, and non-working periods, like weekends or holidays, ensure realistic calculations. Events like dataBound customize scheduling logic on run-time. Taskbars include ARIA labels for accessibility, describing start, end, and duration, and adapt to responsive designs, though narrow screens may require scrolling for long timelines.

Configure scheduling modes

Scheduling modes control task date validation:

  • Auto (default): Validates dates based on dependencies, working time, holidays, and weekends. Parent tasks adjust to child tasks’ minimum start and maximum end dates.
  • Manual: Allows custom dates without automatic validation, editable for parent tasks.
  • Custom: Renders both auto and manual tasks from the data source.

Configure using:

Automatically scheduled Tasks

The following example configures auto scheduling:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { projectData } from './datasource';

function App() {
    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={projectData}
            taskMode="Auto"
            treeColumnIndex={1}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" headerText="Task ID" width="100" />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="150" />
                <ColumnDirective field="Duration" headerText="Duration" width="150" />
                <ColumnDirective field="Progress" headerText="Progress" width="150" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </GanttComponent>
    );
}

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 { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { TaskFieldsModel, EditSettingsModel } from '@syncfusion/ej2-gantt';
import { projectData } from './datasource';

function App() {
    const taskSettings: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={projectData}
            taskMode="Auto"
            treeColumnIndex={1}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" headerText="Task ID" width="100" />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="150" />
                <ColumnDirective field="Duration" headerText="Duration" width="150" />
                <ColumnDirective field="Progress" headerText="Progress" width="150" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </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/32.2.3/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>
<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>

Manually scheduled Tasks

The following example configures manual scheduling:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={data}
            taskMode="Manual"
            treeColumnIndex={1}
            validateManualTasksOnLinking={true}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" headerText="Task ID" width="100" />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="150" />
                <ColumnDirective field="Duration" headerText="Duration" width="150" />
                <ColumnDirective field="Progress" headerText="Progress" width="150" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </GanttComponent>
    );
}

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 { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { TaskFieldsModel, EditSettingsModel } from '@syncfusion/ej2-gantt';
import { data } from './datasource';

function App() {
    const taskSettings: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={data}
            taskMode="Manual"
            treeColumnIndex={1}
            validateManualTasksOnLinking={true}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" headerText="Task ID" width="100" />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="StartDate" headerText="Start Date" width="150" />
                <ColumnDirective field="Duration" headerText="Duration" width="150" />
                <ColumnDirective field="Progress" headerText="Progress" width="150" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </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/32.2.3/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>
<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>

Custom scheduled

The following example mixes auto and manual tasks:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject } from '@syncfusion/ej2-react-gantt';
import { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        manual: 'isManual'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={data}
            taskMode="Custom"
            treeColumnIndex={1}
            validateManualTasksOnLinking={true}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" visible={false} />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="isManual" headerText="Manual" width="100" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </GanttComponent>
    );
}

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 { Edit, Toolbar, Selection } from '@syncfusion/ej2-react-gantt';
import { TaskFieldsModel, EditSettingsModel } from '@syncfusion/ej2-gantt';
import { data } from './datasource';

function App() {
    const taskSettings: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        manual: 'isManual'
    };

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

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

    return (
        <GanttComponent
            height="450px"
            dataSource={data}
            taskMode="Custom"
            treeColumnIndex={1}
            validateManualTasksOnLinking={true}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" visible={false} />
                <ColumnDirective field="TaskName" headerText="Task Name" width="250" />
                <ColumnDirective field="isManual" headerText="Manual" width="100" />
            </ColumnsDirective>
            <Inject services={[Edit, Toolbar, Selection]} />
        </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/32.2.3/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>
<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>

Configure task types

Task types define how changes to duration, work, or resource units affect other properties:

  • FixedUnit (default): Adjusts duration when work changes, maintaining unit allocation.
  • FixedWork: Adjusts duration when units change, maintaining work amount.
  • FixedDuration: Adjusts units when work changes, maintaining duration.

Configure using:

The following example configures task types:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { projectData, resources } from './datasource';

function App() {
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    duration: 'Duration',
    progress: 'Progress',
    resourceInfo: 'resources',
    work: 'Work',
    parentID: 'ParentID'
  };

  const resourceFields = {
    id: 'resourceId',
    name: 'resourceName',
    unit: 'Unit'
  };

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

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

  const columns = [
    { field: 'TaskID', visible: false },
    { field: 'TaskName', headerText: 'Task Name', width: '180' },
    { field: 'resources', headerText: 'Resources', width: '160' },
    { field: 'Work', width: '110' },
    { field: 'Duration', width: '100' },
    { field: 'taskType', headerText: 'Task Type', width: '110' }
  ];

  return (
    <GanttComponent
      height="450px"
      dataSource={projectData}
      taskFields={taskFields}
      columns={columns}
      treeColumnIndex={1}
      editSettings={editSettings}
      allowSelection={true}
      projectStartDate={new Date('03/25/2019')}
      projectEndDate={new Date('04/30/2019')}
      highlightWeekends={true}
      toolbar={toolbar}
      resourceFields={resourceFields}
      resources={resources}
      workUnit="Hour"
      taskType="FixedWork"
    >
    </GanttComponent>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, TaskFieldsModel, ResourceFieldsModel, EditSettingsModel, ColumnModel } from '@syncfusion/ej2-react-gantt';
import { projectData, resources } from './datasource';

function App() {
  const taskFields: TaskFieldsModel = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    duration: 'Duration',
    progress: 'Progress',
    resourceInfo: 'resources',
    work: 'Work',
    parentID: 'ParentID'
  };

  const resourceFields: ResourceFieldsModel = {
    id: 'resourceId',
    name: 'resourceName',
    unit: 'Unit'
  };

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

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

  const columns: ColumnModel = [
    { field: 'TaskID', visible: false },
    { field: 'TaskName', headerText: 'Task Name', width: '180' },
    { field: 'resources', headerText: 'Resources', width: '160' },
    { field: 'Work', width: '110' },
    { field: 'Duration', width: '100' },
    { field: 'taskType', headerText: 'Task Type', width: '110' }
  ];

  return (
    <GanttComponent
      height="450px"
      dataSource={projectData}
      taskFields={taskFields}
      columns={columns}
      treeColumnIndex={1}
      editSettings={editSettings}
      allowSelection={true}
      projectStartDate={new Date('03/25/2019')}
      projectEndDate={new Date('04/30/2019')}
      highlightWeekends={true}
      toolbar={toolbar}
      resourceFields={resourceFields}
      resources={resources}
      workUnit="Hour"
      taskType="FixedWork"
    >
    </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/32.2.3/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>
<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>

Configure duration units

Duration units determine how task length is measured and calculated within the project. The Gantt Chart component supports three duration units that can be applied at both project and individual task levels.

The Gantt Chart component supports the following duration units:

  • Day: Standard for general planning.
  • Hour: For detailed task management.
  • Minute: For short-duration tasks.

Configure using:

The following example maps duration units:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        durationUnit: 'DurationUnit',
        parentID: 'ParentID'
    };

    const splitterSettings = {
        columnIndex: 4
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            splitterSettings={splitterSettings}
        >
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, TaskFieldsModel, SplitterSettingsModel } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskFields: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        durationUnit: 'DurationUnit',
        parentID: 'ParentID'
    };

    const splitterSettings: SplitterSettingsModel = {
        columnIndex: 4
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            splitterSettings={splitterSettings}
        >
        </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/32.2.3/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>
<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>

Defining duration unit with duration value:

The following example defines units in duration values:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

    const splitterSettings = {
        columnIndex: 4
    };

    return (
        <GanttComponent
            id="ganttDefault"
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            splitterSettings={splitterSettings}
            treeColumnIndex={1}
        />
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, SplitterSettingsModel, TaskFieldsModel } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';

function App() {
    const taskFields: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };

    const splitterSettings: SplitterSettingsModel = {
        columnIndex: 4
    };

    return (
        <GanttComponent
            id="ganttDefault"
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            splitterSettings={splitterSettings}
            treeColumnIndex={1}
        />
    );
}

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/32.2.3/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>
<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>

Enable unscheduled tasks

Unscheduled tasks lack start date, end date, or duration, visualized as milestones or single-day tasks. Enable with allowUnscheduledTasks set to true (default: false), defaulting to a 1-day duration from the project start.

Available unscheduled task types:

  • Start date only

    Tasks with only a start date defined, allowing for open-ended planning.

    Start date only task

  • End date only

    Tasks with only an end date defined, useful for deadline-driven activities.

    End date only task

  • Duration only

    Tasks with only duration specified, providing flexibility in scheduling timing.

    Duration only task

  • Milestone

    Special tasks with zero duration representing key project events or deliverables.

    Milestone task

The following example enables unscheduled tasks:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } 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 editSettings = {
        allowEditing: true
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            editSettings={editSettings}
            allowUnscheduledTasks={true}
        />
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, EditSettingsModel, TaskFieldsModel } 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 editSettings: EditSettingsModel = {
        allowEditing: true
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            editSettings={editSettings}
            allowUnscheduledTasks={true}
        />
    );
}

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/32.2.3/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>
<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>

Convert to milestone using method

You can convert a task into a milestone using the ConvertToMilestone method.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Edit } from '@syncfusion/ej2-react-gantt';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { data } from './datasource';

function App() {
    let ganttInstance = null;

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

    const editSettings = {
        allowEditing: true
    };

    const columns = [
        { field: 'TaskID', headerText: 'ID', width: 80 },
        { field: 'TaskName', headerText: 'Name', width: 160 },
        { field: 'StartDate', headerText: 'Start', width: 110, format: 'MM/dd/yyyy' },
        { field: 'EndDate', headerText: 'End', width: 110, format: 'MM/dd/yyyy' },
        { field: 'Duration', headerText: 'Dur', width: 80 },
        { field: 'Progress', headerText: 'Prog', width: 80 }
    ];

    const convertTaskToMilestone = () => {
        if (ganttInstance) {
            ganttInstance.convertToMilestone('6'); // Convert TaskID 6 to milestone
        }
    };

    return (
        <div>
            <div style=>
                <ButtonComponent onClick={convertTaskToMilestone}>Convert Task 6 to Milestone</ButtonComponent>
            </div>
            <GanttComponent
                ref={g => ganttInstance = g}
                height="460px"
                dataSource={data}
                taskFields={taskFields}
                editSettings={editSettings}
                columns={columns}
                allowUnscheduledTasks={true}
            >
                <Inject services={[Edit]} />
            </GanttComponent>
        </div>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Edit, TaskFieldsModel, ColumnModel, EditSettingsModel } from '@syncfusion/ej2-react-gantt';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { data } from './datasource';

function App() {
    let ganttInstance: GanttComponent = null;

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

    const editSettings: EditSettingsModel = {
        allowEditing: true
    };

    const columns: ColumnModel = [
        { field: 'TaskID', headerText: 'ID', width: 80 },
        { field: 'TaskName', headerText: 'Name', width: 160 },
        { field: 'StartDate', headerText: 'Start', width: 110, format: 'MM/dd/yyyy' },
        { field: 'EndDate', headerText: 'End', width: 110, format: 'MM/dd/yyyy' },
        { field: 'Duration', headerText: 'Dur', width: 80 },
        { field: 'Progress', headerText: 'Prog', width: 80 }
    ];

    const convertTaskToMilestone = () => {
        if (ganttInstance) {
            console.log(ganttInstance);
            ganttInstance.convertToMilestone('6'); // Convert TaskID 6 to milestone
        }
    };

    return (
        <div>
            <div style=>
                <ButtonComponent onClick={convertTaskToMilestone}>Convert Task 6 to Milestone</ButtonComponent>
            </div>
            <GanttComponent
                ref={g => ganttInstance = g}
                height="460px"
                dataSource={data}
                taskFields={taskFields}
                editSettings={editSettings}
                columns={columns}
                allowUnscheduledTasks={true}
            >
                <Inject services={[Edit]} />
            </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/32.2.3/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>
<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>

Configure working time range

Working time ranges define productive hours per day, ensuring accurate scheduling calculations. Configure with dayWorkingTime sets project-wide working hours.

The following example sets working hours from 9 AM to 6 PM:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID'
    };
    const timelineSettings = {
        timelineViewMode: 'Day'
    };
    const dayWorkingTime = [{ from: 9, to: 18 }];

    return <GanttComponent dataSource={data} taskFields={taskFields} dayWorkingTime={dayWorkingTime} timelineSettings={timelineSettings} height='450px'>
    </GanttComponent>;
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };
  const timelineSettings = {
    timelineViewMode: 'Day'
  };
  const dayWorkingTime = [{ from: 9, to: 18 }];
  const splitterSettings = {
    position : 0
  }

  return <GanttComponent dataSource={data} taskFields={taskFields} dayWorkingTime={dayWorkingTime} timelineSettings={timelineSettings} splitterSettings={splitterSettings} height='450px'>
  </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/32.2.3/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>
<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>

Non-working days represent periods when project work cannot be performed, such as weekends, holidays, or planned maintenance periods. These settings ensure realistic project scheduling by excluding non-productive time from calculations.

Configure work week

Define which days of the week are considered working days using the workWeek property.

The following example excludes Monday and Tuesday:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, DayMarkers } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };
  const workWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday'];
  return <GanttComponent dataSource={data} taskFields={taskFields} workWeek={workWeek} height='450px'>
    <Inject services={[DayMarkers]} />
  </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, DayMarkers, TaskFieldsModel } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
  const taskFields: TaskFieldsModel = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };
  const workWeek: object = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday'];
  return <GanttComponent dataSource={data} taskFields={taskFields} workWeek={workWeek} height='450px'>
    <Inject services={[DayMarkers]} />
  </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/32.2.3/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>
<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>

Weekend configuration

Configure weekends with:

Customize scheduling with events

Customize scheduling with:

  • dataBound: Adjusts task scheduling after data binding, e.g., switching auto-scheduled tasks to manual mode if their start date precedes the project start date.

The following example uses dataBound to switch auto-scheduled tasks to manual mode if their start date is before the project start date (04/01/2025):

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';

const projectStartDate = new Date('04/01/2025');

const data = [
  { TaskID: 1, TaskName: 'Plan project', StartDate: new Date('04/03/2025'), Duration: 5, isManual: false },
  { TaskID: 2, TaskName: 'Develop feature', StartDate: new Date('04/03/2025'), Duration: 7, isManual: false },
  { TaskID: 3, TaskName: 'Test module', StartDate: new Date('03/31/2025'), Duration: 3, isManual: false }
];

const taskFields = {
  id: 'TaskID',
  name: 'TaskName',
  startDate: 'StartDate',
  duration: 'Duration',
  manual: 'isManual'
};

let ganttInstance = null;

function dataBound() {
  if (!ganttInstance) return;

  const tasks = ganttInstance.dataSource;
  let updated = false;

  tasks.forEach((task: any) => {
    if (!task.isManual && task.StartDate && new Date(task.StartDate) < projectStartDate) {
      task.isManual = true;
      updated = true;
    }
  });

  if (updated) {
    // Create a new array reference to trigger refresh.
    ganttInstance.dataSource = [...tasks];

  }
}

function App() {
  return (
    <GanttComponent
      ref={(gantt) => { ganttInstance = gantt; }}
      dataSource={data}
      height="450px"
      taskMode="Custom"
      taskFields={taskFields}
      dataBound={dataBound}
    />
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';

const projectStartDate: Date = new Date('04/01/2025');

const data: object[] = [
  { TaskID: 1, TaskName: 'Plan project', StartDate: new Date('04/03/2025'), Duration: 5, isManual: false },
  { TaskID: 2, TaskName: 'Develop feature', StartDate: new Date('04/03/2025'), Duration: 7, isManual: false },
  { TaskID: 3, TaskName: 'Test module', StartDate: new Date('03/31/2025'), Duration: 3, isManual: false }
];

const taskFields: object = {
  id: 'TaskID',
  name: 'TaskName',
  startDate: 'StartDate',
  duration: 'Duration',
  manual: 'isManual'
};

let ganttInstance: GanttComponent = null;

function dataBound() {
  if (!ganttInstance) return;

  const tasks = ganttInstance.dataSource;
  let updated = false;

  tasks.forEach((task: any) => {
    if (!task.isManual && task.StartDate && new Date(task.StartDate) < projectStartDate) {
      task.isManual = true;
      updated = true;
    }
  });

  if (updated) {
    // Create a new array reference to trigger refresh.
    ganttInstance.dataSource = [...tasks];

  }
}

function App() {
  return (
    <GanttComponent
      ref={(gantt) => { ganttInstance = gantt; }}
      dataSource={data}
      height="450px"
      taskMode="Custom"
      taskFields={taskFields}
      dataBound={dataBound}
    />
  );
}

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/32.2.3/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>
<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>

See also