Taskbar in React Gantt Chart Component

31 Jan 202624 minutes to read

The taskbar in the React Gantt Chart component visually represents tasks on the timeline, showing duration, progress, and dependencies, enabling intuitive project management. Taskbars support customization through properties like taskbarHeight for sizing and queryTaskbarInfo event for conditional formatting based on task data like progress. Multi-taskbar support in resource view, enabled by enableMultiTaskbar, summarizes child task progress in collapsed parent taskbars. Connector lines, styled via connectorLineWidth and connectorLineBackground, illustrate dependencies. Tooltips, controlled by tooltipSettings, provide hover details for taskbars, baselines, and timelines, with templates for custom content. Editing interactions include dragging for rescheduling (via allowTaskbarDragAndDrop) and resizing for duration, progress changes, triggering events like taskbarEditing and taskbarEdited for validation.

Customize taskbar height

Taskbar height for child and parent tasks is set using the taskbarHeight property, which accepts pixel values and must be less than rowHeight to avoid overflow.

The following example demonstrates how to set a custom taskbar height of 40 pixels, delivering consistent appearance across tasks while preserving full responsiveness.

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',
  };
  return <GanttComponent dataSource={data} taskFields={taskFields} rowHeight={50}
    taskbarHeight={40} 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: any = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID',
  };
  return <GanttComponent dataSource={data} taskFields={taskFields} rowHeight={50}
    taskbarHeight={40} 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.1.19/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>

Apply conditional formatting

Conditional formatting replaces default taskbar appearance using the queryTaskbarInfo event, accessing task data to modify colors, progress bars, or styles based on criteria like progress.

This example demonstrates formatting taskbars based on progress, where args.data.progress in the event handler dynamically sets args.taskbarBgColor and args.progressBarBgColor to visually highlight critical tasks or milestones.

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

function App() {
    let gantt = null;

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

    const queryTaskbarInfo = (args) => {
        const record = args.data;

        if (record.Progress === 50) {
            args.progressBarBgColor = 'red';
        } else if (record.Progress === 70) {
            args.progressBarBgColor = 'yellow';
        } else if (record.Progress === 80) {
            args.progressBarBgColor = 'lightgreen';
        }
    };

    return (
        <GanttComponent id="ganttDefault" height="430px" dataSource={data} taskFields={taskFields} queryTaskbarInfo={queryTaskbarInfo} ref={(g) => (gantt = g)}>
            <Inject services={[Selection, Filter, Toolbar]} />
        </GanttComponent>
    );
}

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

function App() {
    let gantt: GanttComponent | null = null;

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

    const queryTaskbarInfo = (args: IQueryTaskbarInfoEventArgs): void => {
        const record: any = args.data;

        if (record.Progress === 50) {
            args.progressBarBgColor = 'red';
        } else if (record.Progress === 70) {
            args.progressBarBgColor = 'yellow';
        } else if (record.Progress === 80) {
            args.progressBarBgColor = 'lightgreen';
        }
    };

    return (
        <GanttComponent id="ganttDefault" height="430px" dataSource={data} taskFields={taskFields} queryTaskbarInfo={queryTaskbarInfo} ref={(g) => (gantt = g)}>
            <Inject services={[Selection, Filter, Toolbar]} />
        </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.1.19/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>

Customize gripper icons

Gripper icons for taskbar editing (start, end, progress) are customized by targeting CSS classes like .e-gantt-left-resize-gripper or .e-gantt-right-resize-gripper with custom styles, overriding default icons for branded appearances.

In the following example, the progress gripper icon is customized by targeting the .e-gantt-progress-resize-gripper class. The custom styles also ensure touch-friendly sizing to support responsive and accessible user interactions.

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

function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        dependency: 'Predecessor',
    };
    const editSettings = {
        allowEditing: true,
        editMode: 'Auto',
        allowTaskbarEditing: true
    };
    return <GanttComponent dataSource={data} taskFields={taskFields} editSettings={editSettings} height='400px'>
        <Inject services={[Edit]} />
    </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import { GanttComponent, Inject, Edit, TaskFieldsModel, EditSettingsModel } from '@syncfusion/ej2-react-gantt';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { data } from './datasource';

function App() {
    const taskFields: TaskFieldsModel = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        dependency: 'Predecessor',
    };
    const editSettings: EditSettingsModel = {
        allowEditing: true,
        editMode: 'Auto',
        allowTaskbarEditing: true
    };
    return <GanttComponent dataSource={data} taskFields={taskFields} editSettings={editSettings} height='400px'>
        <Inject services={[Edit]} />
    </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.1.19/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%;
        }

        /* change gripper icon */
        .e-gantt .e-left-resize-gripper::before,
        .e-gantt .e-right-resize-gripper::before {
            content: '\e934';
        }

        .e-gantt .e-left-resize-gripper,
        .e-gantt .e-right-resize-gripper {
            transform: rotate(90deg);
        }
    </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>

Control taskbar and notes icon visibility

Taskbars and notes icons can be hidden dynamically using the queryTaskbarInfo and queryCellInfo events, enabling conditional visibility based on task data (e.g., hiding milestones or empty notes for cleaner timelines). Hiding taskbars affects only the timeline element, not the row or labels, and requires taskFields.notes for notes icon rendering.

The following example hides taskbars for specific tasks and notes icons for empty notes:

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

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

    const queryTaskbarInfo = (args) => {
        const task = args.data;
        if (task.TaskID >= 7 && task.TaskID <= 10) {
            (args.taskbarElement).style.visibility = 'hidden';
        }
    };

    const queryCellInfo = (args) => {
        const task = args.data;
        if (args.column.field === 'Info' && (!task.Info || task.Info.trim() === '')) {
            const notesIcon = (args.cell).querySelector('.e-notes-info');
            if (notesIcon instanceof HTMLElement) {
                notesIcon.style.visibility = 'hidden';
            }
        }
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            queryTaskbarInfo={queryTaskbarInfo}
            queryCellInfo={queryCellInfo}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" width="80" />
                <ColumnDirective field="TaskName" headerText="Task Name" />
                <ColumnDirective field="StartDate" />
                <ColumnDirective field="Duration" />
                <ColumnDirective field="Progress" />
                <ColumnDirective field="Info" headerText="Notes" />
            </ColumnsDirective>
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, QueryTaskbarInfoEventArgs, QueryCellInfoEventArgs, ColumnsDirective, ColumnDirective, 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',
        notes: 'Info'
    };

    const queryTaskbarInfo = (args: QueryTaskbarInfoEventArgs): void => {
        const task = args.data;
        if (task.TaskID >= 7 && task.TaskID <= 10) {
            (args.taskbarElement as HTMLElement).style.visibility = 'hidden';
        }
    };

    const queryCellInfo = (args: QueryCellInfoEventArgs): void => {
        const task = args.data;
        if (args.column.field === 'Info' && (!task.Info || task.Info.trim() === '')) {
            const notesIcon = (args.cell as HTMLElement).querySelector('.e-notes-info');
            if (notesIcon instanceof HTMLElement) {
                notesIcon.style.visibility = 'hidden';
            }
        }
    };

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            queryTaskbarInfo={queryTaskbarInfo}
            queryCellInfo={queryCellInfo}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskID" width="80" />
                <ColumnDirective field="TaskName" headerText="Task Name" />
                <ColumnDirective field="StartDate" />
                <ColumnDirective field="Duration" />
                <ColumnDirective field="Progress" />
                <ColumnDirective field="Info" headerText="Notes" />
            </ColumnsDirective>
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/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>

This code hides taskbars for tasks with IDs 7–10 (e.g., estimation tasks) and notes icons for empty Info fields, using queryTaskbarInfo and queryCellInfo. The .e-notes-info class ensures robust icon targeting, and taskFields.notes enables notes rendering.

Prevent taskbar editing for specific tasks

Taskbar editing, including dragging, resizing, or adding dependencies, can be prevented for specific tasks (e.g., locked milestones or completed tasks) using the actionBegin event for validation and queryTaskbarInfo to hide editing UI elements like grippers and connector points. This ensures visual and functional restrictions, with ARIA attributes updated for accessibility.

The following example disables taskbar editing for Task ID 4 by canceling drag, resize, and dependency actions in the actionBegin event and hiding resize grippers and connector points in queryTaskbarInfo using CSS classes. Editing remains enabled for other tasks through the Edit service injection and the allowTaskbarEditing property, while global CSS ensures the styles are applied to the Gantt Chart component’s DOM.

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

const taskData = [
  { TaskId: 1, TaskName: 'Product Concept', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
  { TaskId: 2, TaskName: 'Defining the product and its usage', StartDate: new Date('04/02/2019'), Duration: 3, Progress: 30, ParentId: 1 },
  { TaskId: 3, TaskName: 'Defining target audience', StartDate: new Date('04/02/2019'), Duration: 3, ParentId: 1 },
  { TaskId: 4, TaskName: 'Prepare product sketch and notes', StartDate: new Date('04/02/2019'), Duration: 2, Predecessor: '2', Progress: 30, ParentId: 1 },
  { TaskId: 5, TaskName: 'Concept Approval', StartDate: new Date('04/02/2019'), Duration: 0, Predecessor: '3,4', Indicators: [{ date: '04/10/2019', name: '#briefing', title: 'Product concept briefing' }] },
  { TaskId: 6, TaskName: 'Market Research', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
  { TaskId: 7, TaskName: 'Demand Analysis', StartDate: new Date('04/04/2019'), EndDate: new Date('04/21/2019'), ParentId: 6 },
  { TaskId: 8, TaskName: 'Customer strength', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '5', Progress: 30, ParentId: 7 },
  { TaskId: 9, TaskName: 'Market opportunity analysis', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '5', ParentId: 7 },
  { TaskId: 10, TaskName: 'Competitor Analysis', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '7, 8', Progress: 30, ParentId: 6 }
];

function App() {
  let gantt = null;

  const taskSettings = { id: 'TaskId', name: 'TaskName', startDate: 'StartDate', duration: 'Duration', progress: 'Progress', parentID: 'ParentId' };
  const labelSettings = { leftLabel: 'TaskName' };
  const editSettings = { allowTaskbarEditing: true };

  const projectStartDate = new Date('03/28/2019');
  const projectEndDate = new Date('04/18/2019');

  const queryTaskbarInfo = (args) => {
    if (args.data.TaskId === 4) {
      args.taskbarElement.style.cursor = 'default';
      args.taskbarElement.classList.add('e-prevent-reschedule', 'e-prevent-add-relation-left', 'e-prevent-add-relation-right');
    }
  };

  const actionBegin = (args) => {
    if (args.data.TaskId === 4 && [
      'ChildDrag', 'ProgressResizing', 'LeftResizing', 'RightResizing',
      'ConnectorPointLeftDrag', 'ConnectorPointRightDrag'
    ].includes(args.taskBarEditAction)) {
      args.cancel = true;
    }
  };

  return (
    <GanttComponent
      id="ganttDefault"
      height="430px"
      dataSource={taskData}
      taskFields={taskSettings}
      labelSettings={labelSettings}
      projectStartDate={projectStartDate}
      projectEndDate={projectEndDate}
      editSettings={editSettings}
      queryTaskbarInfo={queryTaskbarInfo}
      actionBegin={actionBegin}
      ref={(g) => (gantt = g)}
    >
      <Inject services={[Edit, Selection]} />
    </GanttComponent>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Edit, Selection, IActionBeginEventArgs, IQueryTaskbarInfoEventArgs, TaskFieldsModel, LabelSettingsModel, EditSettingsModel } from '@syncfusion/ej2-react-gantt';

const taskData: object[] = [
  { TaskId: 1, TaskName: 'Product Concept', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
  { TaskId: 2, TaskName: 'Defining the product and its usage', StartDate: new Date('04/02/2019'), Duration: 3, Progress: 30, ParentId: 1 },
  { TaskId: 3, TaskName: 'Defining target audience', StartDate: new Date('04/02/2019'), Duration: 3, ParentId: 1 },
  { TaskId: 4, TaskName: 'Prepare product sketch and notes', StartDate: new Date('04/02/2019'), Duration: 2, Predecessor: '2', Progress: 30, ParentId: 1 },
  { TaskId: 5, TaskName: 'Concept Approval', StartDate: new Date('04/02/2019'), Duration: 0, Predecessor: '3,4', Indicators: [{ date: '04/10/2019', name: '#briefing', title: 'Product concept briefing' }] },
  { TaskId: 6, TaskName: 'Market Research', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
  { TaskId: 7, TaskName: 'Demand Analysis', StartDate: new Date('04/04/2019'), EndDate: new Date('04/21/2019'), ParentId: 6 },
  { TaskId: 8, TaskName: 'Customer strength', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '5', Progress: 30, ParentId: 7 },
  { TaskId: 9, TaskName: 'Market opportunity analysis', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '5', ParentId: 7 },
  { TaskId: 10, TaskName: 'Competitor Analysis', StartDate: new Date('04/04/2019'), Duration: 4, Predecessor: '7, 8', Progress: 30, ParentId: 6 }
];

function App() {
  let gantt: GanttComponent | null = null;

  const taskSettings: TaskFieldsModel = { id: 'TaskId', name: 'TaskName', startDate: 'StartDate', duration: 'Duration', progress: 'Progress', parentID: 'ParentId' };
  const labelSettings: LabelSettingsModel = { leftLabel: 'TaskName' };
  const editSettings: EditSettingsModel = { allowTaskbarEditing: true };

  const projectStartDate: Date = new Date('03/28/2019');
  const projectEndDate: Date = new Date('04/18/2019');

  const queryTaskbarInfo = (args: IQueryTaskbarInfoEventArgs): void => {
    if ((args.data as any).TaskId === 4) {
      args.taskbarElement.style.cursor = 'default';
      args.taskbarElement.classList.add('e-prevent-reschedule', 'e-prevent-add-relation-left', 'e-prevent-add-relation-right');
    }
  };

  const actionBegin = (args: IActionBeginEventArgs): void => {
    if (args.data.TaskId === 4 && [
      'ChildDrag', 'ProgressResizing', 'LeftResizing', 'RightResizing',
      'ConnectorPointLeftDrag', 'ConnectorPointRightDrag'
    ].includes(args.taskBarEditAction)) {
      args.cancel = true;
    }
  };

  return (
    <GanttComponent
      id="ganttDefault"
      height="430px"
      dataSource={taskData}
      taskFields={taskSettings}
      labelSettings={labelSettings}
      projectStartDate={projectStartDate}
      projectEndDate={projectEndDate}
      editSettings={editSettings}
      queryTaskbarInfo={queryTaskbarInfo}
      actionBegin={actionBegin}
      ref={(g) => (gantt = g)}
    >
      <Inject services={[Edit, 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.1.19/tailwind3.css" rel="stylesheet" type="text/css" />
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }

        .e-gantt-chart .e-prevent-reschedule .e-right-resize-gripper,
        .e-gantt-chart .e-prevent-reschedule .e-left-resize-gripper,
        .e-gantt-chart .e-prevent-reschedule .e-progress-resize-gripper {
            display: none !important;
        }

        .e-gantt-chart .e-prevent-add-relation-left .e-left-connectorpoint-outer-div {
            display: none !important;
        }

        .e-gantt-chart .e-prevent-add-relation-right .e-right-connectorpoint-outer-div {
            display: none !important;
        }
    </style>
</head>

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

</html>

Customize taskbar templates

Taskbar templates allow full replacement of the default taskbar UI, enabling custom designs such as progress bars, badges, or icons. You can customize task rendering using the taskbarTemplate property for child tasks. You can also use parentTaskbarTemplate for parent tasks and milestoneTemplate for milestones. The taskbarTemplate function receives a props object that contains task-specific details and computed ganttProperties, such as the taskbar width and progress value. These properties can be used to dynamically calculate dimensions and control the visual presentation of the taskbar. For advanced conditional styling or logic, the queryTaskbarInfo event can be used.

This example renders a custom taskbar with a progress bar and a badge showing the task’s progress percentage. The progress bar width is calculated from the taskbar width and progress value in props.ganttProperties, ensuring each taskbar displays accurate progress at runtime.

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

function App() {
    const taskData = [
        { TaskID: 1, TaskName: 'Product Concept', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
        { TaskID: 2, TaskName: 'Defining the product and its usage', StartDate: new Date('04/02/2019'), Duration: 3, Progress: 30, ParentID: 1 },
        { TaskID: 3, TaskName: 'Defining target audience', StartDate: new Date('04/02/2019'), Duration: 3, ParentID: 1 },
        { TaskID: 4, TaskName: 'Prepare product sketch and notes', StartDate: new Date('04/02/2019'), Duration: 2, Predecessor: '2', Progress: 30, ParentID: 1 },
        { TaskID: 5, TaskName: 'Concept Approval', StartDate: new Date('04/10/2019'), Duration: 0, Predecessor: '3,4', Indicators: [{ date: '04/10/2019', name: '#briefing', title: 'Product concept briefing' }] }
    ];

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

    const labelSettings = { leftLabel: 'TaskName' };

    const taskbarTemplate = (props) => {
        const width = props.ganttProperties.width;
        const progress = props.ganttProperties.progress || 0;
        const progressWidth = (progress * width) / 100;

        return (
            <div className="e-gantt-child-taskbar-inner-div e-gantt-child-taskbar">
                <div className="e-gantt-child-progressbar-inner-div e-gantt-child-progressbar" style={{ width: `${progressWidth}px`, height: '100%' }}></div>
                <span className="e-badge e-badge-primary" style={{ marginLeft: '6px' }}>{progress}%</span>
            </div>
        );
    };

    const projectStartDate = new Date('03/28/2019');
    const projectEndDate= new Date('04/18/2019');

    return (
        <GanttComponent
            id="Gantt"
            height="450px"
            dataSource={taskData}
            taskFields={taskFields}
            labelSettings={labelSettings}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            taskbarTemplate={taskbarTemplate}
        />
    );
}

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

function App() {
    const taskData = [
        { TaskID: 1, TaskName: 'Product Concept', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019') },
        { TaskID: 2, TaskName: 'Defining the product and its usage', StartDate: new Date('04/02/2019'), Duration: 3, Progress: 30, ParentID: 1 },
        { TaskID: 3, TaskName: 'Defining target audience', StartDate: new Date('04/02/2019'), Duration: 3, ParentID: 1 },
        { TaskID: 4, TaskName: 'Prepare product sketch and notes', StartDate: new Date('04/02/2019'), Duration: 2, Predecessor: '2', Progress: 30, ParentID: 1 },
        { TaskID: 5, TaskName: 'Concept Approval', StartDate: new Date('04/10/2019'), Duration: 0, Predecessor: '3,4', Indicators: [{ date: '04/10/2019', name: '#briefing', title: 'Product concept briefing' }] }
    ];

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

    const labelSettings = { leftLabel: 'TaskName' };

    const taskbarTemplate = (props) => {
        const width = props.ganttProperties.width;
        const progress = props.ganttProperties.progress || 0;
        const progressWidth = (progress * width) / 100;

        return (
            <div className="e-gantt-child-taskbar-inner-div e-gantt-child-taskbar">
                <div className="e-gantt-child-progressbar-inner-div e-gantt-child-progressbar" style={{ width: `${progressWidth}px`, height: '100%' }}></div>
                <span className="e-badge e-badge-primary" style={{ marginLeft: '6px' }}>{progress}%</span>
            </div>
        );
    };

    const projectStartDate = new Date('03/28/2019');
    const projectEndDate= new Date('04/18/2019');

    return (
        <GanttComponent
            id="Gantt"
            height="450px"
            dataSource={taskData}
            taskFields={taskFields}
            labelSettings={labelSettings}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            taskbarTemplate={taskbarTemplate}
        />
    );
}

ReactDOM.render(<App />, document.getElementById('root'));

Enable multi-taskbar support

In project view, multi-taskbar support, enabled by enableMultiTaskbar, renders parent taskbars summarizing child progress when collapsed, providing aggregated visualization.

The following example enables multi-taskbar:

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

function App() {

  const data = projectViewMultiTaskData;

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

  return (
    <GanttComponent
      id="Gantt"
      height="430px"
      dataSource={data}
      taskFields={taskSettings}
      enableMultiTaskbar={true}
      treeColumnIndex={1}
      allowSelection={true}
    />
  );
}

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

function App() {

  const data: object[] = projectViewMultiTaskData;

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

  return (
    <GanttComponent
      id="Gantt"
      height="430px"
      dataSource={data}
      taskFields={taskSettings}
      enableMultiTaskbar={true}
      treeColumnIndex={1}
      allowSelection={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.1.19/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>

This feature aggregates child progress in parent taskbars, updating dynamically on child changes.

Customize connector lines

Connector lines for dependencies are styled using connectorLineWidth for thickness and connectorLineBackground for color, enhancing dependency visibility.

The following example demonstrates connector customization. The specified properties are applied globally to all connectors, while the queryTaskbarInfo event supports per-dependency customization through the args.connectorLineBackground property.

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',
        dependency: 'Predecessor',
        parentID: 'ParentID'
    };
    return <GanttComponent dataSource={data} taskFields={taskFields}
        connectorLineWidth={3} connectorLineBackground='red' height='450px'>
    </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, 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',
        dependency: 'Predecessor',
        parentID: 'ParentID'
    };
    return <GanttComponent dataSource={data} taskFields={taskFields}
        connectorLineWidth={3} connectorLineBackground='red' 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.1.19/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 tooltips

Tooltips for taskbars, connectors, baselines, and event markers are enabled by default via tooltipSettings.showTooltip, set to true. Disable for specific elements or customize content with templates.

The following example enables tooltips:

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

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

  const tooltipSettings = {
    showTooltip: true
  };

  const eventMarkers = [
    {
      day: '04/10/2019',
      label: 'Project approval and kick-off'
    }
  ];

  return (
    <GanttComponent
      height="430px"
      dataSource={data}
      taskFields={taskFields}
      renderBaseline={true}
      baselineColor="red"
      treeColumnIndex={1}
      tooltipSettings={tooltipSettings}
      eventMarkers={eventMarkers}
    >
      <Inject services={[Selection, DayMarkers]} />
    </GanttComponent>
  );
}

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

import { data } from './datasource';

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

  const tooltipSettings: TooltipSettingsModel = {
    showTooltip: true
  };

  const eventMarkers: EventMarkerModel[] = [
    {
      day: '04/10/2019',
      label: 'Project approval and kick-off'
    }
  ];

  return (
    <GanttComponent
      height="430px"
      dataSource={data}
      taskFields={taskFields}
      renderBaseline={true}
      baselineColor="red"
      treeColumnIndex={1}
      tooltipSettings={tooltipSettings}
      eventMarkers={eventMarkers}
    >
      <Inject services={[Selection, 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.1.19/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>

Tooltips display on hover, with touch-and-hold support for mobile via the tooltip popup.

Disable taskbar tooltip

You can disable the taskbar tooltip using the beforeTooltipRender event by setting args.cancel to true.

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',
    dependency: 'Predecessor',
    parentID: 'ParentID',
    baselineStartDate: 'BaselineStartDate',
    baselineEndDate: 'BaselineEndDate'
  };

  const tooltipSettings = {
    showTooltip: true
  };

  const beforeTooltipRender = (args) => {
    if (
      args.args.target.classList.contains('e-gantt-child-taskbar') ||
      args.args.target.classList.contains('e-gantt-parent-taskbar') ||
      args.args.target.classList.contains('e-taskbar-left-resizer') ||
      args.args.target.classList.contains('e-taskbar-right-resizer')
    ) {
      args.cancel = true;
    }
  };

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

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

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

  const tooltipSettings: TooltipSettingsModel = {
    showTooltip: true
  };

  const beforeTooltipRender = (args: BeforeTooltipRenderEventArgs): void => {
    if (
      args.args.target.classList.contains('e-gantt-child-taskbar') ||
      args.args.target.classList.contains('e-gantt-parent-taskbar') ||
      args.args.target.classList.contains('e-taskbar-left-resizer') ||
      args.args.target.classList.contains('e-taskbar-right-resizer')
    ) {
      args.cancel = true;
    }
  };

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

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.1.19/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>

Customize tooltip templates

You can customize the following tooltip types in the Gantt chart using the tooltipSettings configuration:

Taskbar tooltip

Taskbar tooltips are customized using tooltipSettings.taskbar template, accessing task data for formatted content.

The following example customizes taskbar tooltips:

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'
  };
  function tooltipTemplate(props) {
    return (<div>TaskID : {props.TaskID}</div>)
  };
  const template = tooltipTemplate;
  const tooltipSettings = {
    taskbar: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} 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: any = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };
  function tooltipTemplate(props: any) {
    return (<div>TaskID : {props.TaskID}</div>)
  };
  const template: any = tooltipTemplate;
  const tooltipSettings: any = {
    taskbar: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} 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.1.19/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>

The template uses data to display fields like TaskName and Progress, ensuring responsive display.

Connector line tooltip

Connector tooltips, customized via tooltipSettings.connectorLine, show dependency details like type and offset.

The following example customizes connector tooltips:

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

function App() {
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    dependency: 'Predecessor',
    parentID: 'ParentID'
  };
  function tooltipTemplate(props) {
    return (<div>Offset : {props.offsetString}</div>)
  };
  const template = tooltipTemplate;
  const tooltipSettings = {
    connectorLine: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} height='450px'>
    <ColumnsDirective>
      <ColumnDirective field='TaskID' width='100' ></ColumnDirective>
      <ColumnDirective field='Predecessor'></ColumnDirective>
    </ColumnsDirective>
  </GanttComponent>

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

function App() {
  const taskFields: any = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    dependency: 'Predecessor',
    parentID: 'ParentID'
  };
  function tooltipTemplate(props: any) {
    return (<div>Offset : {props.offsetString}</div>)
  };
  const template: any = tooltipTemplate;
  const tooltipSettings: any = {
    connectorLine: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} height='450px'>
    <ColumnsDirective>
      <ColumnDirective field='TaskID' width='100' ></ColumnDirective>
      <ColumnDirective field='Predecessor'></ColumnDirective>
    </ColumnsDirective>
  </GanttComponent>

};
ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/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>

Baseline tooltip

A baseline tooltip can be customized using the tooltipSettings.baseline property.

The following example customizes baseline tooltips:

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

 } from './datasource';
function App() {
  let ganttInstance;
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    baselineStartDate: 'BaselineStartDate',
    baselineEndDate: 'BaselineEndDate',
    parentID: 'ParentID'
  };
  function tooltipTemplate(props) {
    return (<div>Baseline StartDate : {ganttInstance.getFormatedDate(props.BaselineStartDate)}</div>)
  };
  const template = tooltipTemplate;
  const tooltipSettings = {
    baseline: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} renderBaseline={true} baselineColor="red" height='450px' ref={gantt => ganttInstance = gantt}>
  </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, TaskFieldsModel } from '@syncfusion/ej2-react-gantt';
import { data

 } from './datasource';
function App() {
  let ganttInstance: GanttComponent;
  const taskFields: TaskFieldsModel = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    duration: 'Duration',
    progress: 'Progress',
    baselineStartDate: 'BaselineStartDate',
    baselineEndDate: 'BaselineEndDate',
    parentID: 'ParentID'
  };
  function tooltipTemplate(props: any) {
    return (<div>Baseline StartDate : {ganttInstance.getFormatedDate(props.BaselineStartDate)}</div>)
  };
  const template: any = tooltipTemplate;
  const tooltipSettings: any = {
    baseline: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} renderBaseline={true} baselineColor="red" height='450px' ref={gantt => ganttInstance = gantt}>
  </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.1.19/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>

Timeline tooltip

Timeline tooltips, customized with tooltipSettings.timeline, display date details.

The following example customizes timeline tooltips:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
  let ganttInstance;
  const taskFields = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };
  function timelineTooltip(props) {
    const tier = props.tier;
    const date = props.date;
    const endDate = new Date(date);
    if (tier === 'topTier' && ganttInstance.timelineSettings.topTier.unit) {
      endDate.setDate(endDate.getDate() + 6);
    }
    const data = getTooltipData(new Date(date), endDate, tier);

    return (
      <div style=>
        <div style=>
          <span style=>
            {tier === 'topTier' ? props.value : date}
          </span>
        </div>
        <div style=>
          <span style=>Active Tasks:</span>
          <span style=>{data.activeTasks}</span>
        </div>
        <div style=>
          <span style=>Milestones:</span>
          <span style=>{data.milestones}</span>
        </div>
        <div style=>
          <span style=>Overall Progress:</span>
          <span style=>{data.overallProgress}</span>
        </div>
      </div>
    );
  };

  const getTooltipData = (startDate, endDate, tier) => {
    const gantt = ganttInstance;
    let activeTasks = [];

    if (tier === 'topTier') {
      activeTasks = gantt.currentViewData.filter((task) => {
        const taskStart = new Date(task['StartDate']);
        const taskEnd = new Date(task['EndDate']);
        taskStart.setHours(0, 0, 0, 0);
        taskEnd.setHours(0, 0, 0, 0);
        return (taskStart >= startDate && taskEnd <= endDate);
      });
    } else {
      activeTasks = gantt.currentViewData.filter((task) => {
        const taskStart = new Date(task['StartDate']);
        const taskEnd = new Date(task['EndDate']);
        taskStart.setHours(0, 0, 0, 0);
        taskEnd.setHours(0, 0, 0, 0);
        return (taskStart.getTime() === startDate.getTime() && taskEnd.getTime() === endDate.getTime());
      });
    }

    const milestones = activeTasks.filter((task) => task.Duration === 0);
    const totalProgress = activeTasks.reduce((acc, task) => acc + (task.Progress || 0), 0);
    const overallProgress = (activeTasks.length > 0) ? (totalProgress / activeTasks.length).toFixed(2) : '0';

    return {
      activeTasks: activeTasks.length,
      milestones: milestones.length,
      overallProgress: overallProgress
    };
  }
  const template = timelineTooltip;
  const tooltipSettings = {
    timeline: template
  };
  return <GanttComponent dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} height='450px' ref={gantt => ganttInstance = gantt}>
  </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() {
  let ganttInstance: GanttComponent;
  const taskFields: any = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID'
  };

  function timelineTooltip(props: any) {
    const tier = props.tier;
    const date = props.date;
    const endDate = new Date(date);
    if (tier === 'topTier' && ganttInstance.timelineSettings.topTier.unit) {
      endDate.setDate(endDate.getDate() + 6);
    }
    const data = getTooltipData(new Date(date), endDate, tier);

    return (
      <div style=>
        <div style=>
          <span style=>
            {tier === 'topTier' ? props.value : date}
          </span>
        </div>
        <div style=>
          <span style=>Active Tasks:</span>
          <span style=>{data.activeTasks}</span>
        </div>
        <div style=>
          <span style=>Milestones:</span>
          <span style=>{data.milestones}</span>
        </div>
        <div style=>
          <span style=>Overall Progress:</span>
          <span style=>{data.overallProgress}</span>
        </div>
      </div>
    );
  };

  const getTooltipData = (startDate: Date, endDate: Date, tier: string) => {
    const gantt = ganttInstance;
    let activeTasks: any = [];

    if (tier === 'topTier') {
      activeTasks = gantt.currentViewData.filter((task: any) => {
        const taskStart = new Date(task['StartDate']);
        const taskEnd = new Date(task['EndDate']);
        taskStart.setHours(0, 0, 0, 0);
        taskEnd.setHours(0, 0, 0, 0);
        return (taskStart >= startDate && taskEnd <= endDate);
      });
    } else {
      activeTasks = gantt.currentViewData.filter((task: any) => {
        const taskStart = new Date(task['StartDate']);
        const taskEnd = new Date(task['EndDate']);
        taskStart.setHours(0, 0, 0, 0);
        taskEnd.setHours(0, 0, 0, 0);
        return (taskStart.getTime() === startDate.getTime() && taskEnd.getTime() === endDate.getTime());
      });
    }

    const milestones = activeTasks.filter((task: any) => task.Duration === 0);
    const totalProgress = activeTasks.reduce((acc: any, task: any) => acc + (task.Progress || 0), 0);
    const overallProgress = (activeTasks.length > 0) ? (totalProgress / activeTasks.length).toFixed(2) : '0';

    return {
      activeTasks: activeTasks.length,
      milestones: milestones.length,
      overallProgress: overallProgress
    };
  }
  const template: any = timelineTooltip;
  const tooltipSettings: any = {
    timeline: template
  };
  return <GanttComponent ref={gantt => ganttInstance = gantt} dataSource={data} taskFields={taskFields}
    tooltipSettings={tooltipSettings} 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.1.19/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>

Tooltip Touch interaction

To perform touch and hold action on a element, refer to tooltip popup.

See also