Syncfusion AI Assistant

How can I help you?

Resources in React Gantt Chart Component

12 Mar 202624 minutes to read

Resources in the React Gantt Chart component represent people, equipment, or materials allocated to tasks, visualized in taskbars and labels for clear utilization tracking. Assigned via the resources property, resources map to tasks using resourceFields for ID, name, unit, and group. This enables display of resource names in columns or labels with labelSettings, highlighting workloads and overallocation. The queryTaskbarInfo event customizes taskbar styles based on resources, such as color-coding. Resources include ARIA labels for accessibility, ensuring screen reader compatibility, and adapt to responsive designs, though narrow screens may truncate names for multiple assignments. By default, resources allocate 100% unit if unspecified.

Configure resource collection

The resource collection defines available resources as JSON objects with ID, name, unit, and group, mapped via resourceFields:

  • id: Maps to a unique identifier for task assignment.
  • name: Maps to the resource name displayed in labels or columns.
  • unit: Maps to the work capacity percentage (0-100%) per day.
  • group: Maps to categories for grouping resources.

The following code demonstrates resource collection setup:

const projectResources: Object[] = [
    { resourceId: 1, resourceName: 'Martin Tamer', resourceGroup: 'Planning Team', resourceUnit: 50 },
    { resourceId: 2, resourceName: 'Rose Fuller', resourceGroup: 'Testing Team', resourceUnit: 70 },
    { resourceId: 3, resourceName: 'Margaret Buchanan', resourceGroup: 'Approval Team' },
    { resourceId: 4, resourceName: 'Fuller King', resourceGroup: 'Development Team' },
    { resourceId: 5, resourceName: 'Davolio Fuller', resourceGroup: 'Approval Team' },
    { resourceId: 6, resourceName: 'Van Jack', resourceGroup: 'Development Team', resourceUnit: 40 }
];

const resourceFields: ResourceFieldsModel = {
    id: 'resourceId',
    name: 'resourceName',
    unit: 'resourceUnit',
    group: 'resourceGroup'
};

This configuration maps resources for assignment and display.

Assign resources to tasks

Resources are assigned to tasks using resource IDs in the data source, mapped via taskFields.resourceInfo. Assignments can be added or edited dynamically via cell or dialog editing, triggered by double-clicking.

Single resource assignment:
Assign a single resource without unit for default 100% allocation.

{ 
    TaskID: 2, 
    TaskName: 'Identify site location', 
    StartDate: new Date('04/02/2019'), 
    Duration: 0, 
    Progress: 50, 
    resources: [1] 
}

Multiple resources with custom units:
Assign multiple resources with specific units.

{
    TaskID: 2, 
    TaskName: 'Identify site location', 
    StartDate: new Date('03/29/2019'), 
    Duration: 2,
    Progress: 30,  
    resources: [{ resourceId: 1, unit: 70 }, 6]
}

Units from the resource collection apply unless overridden at the task level.

The following example shows resource assignment:

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

function App() {

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

    const labelSettings = {
        leftLabel: 'TaskName',
        rightLabel: 'resources'
    };

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

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

    const projectStartDate = new Date('03/25/2019');
    const projectEndDate = new Date('07/28/2019');

    const resources = [
        { resourceId: 1, resourceName: 'Martin Tamer' },
        { resourceId: 2, resourceName: 'Rose Fuller' },
        { resourceId: 3, resourceName: 'Margaret Buchanan' },
        { resourceId: 4, resourceName: 'Fuller King' },
        { resourceId: 5, resourceName: 'Davolio Fuller' },
        { resourceId: 6, resourceName: 'Van Jack' },
        { resourceId: 7, resourceName: 'Fuller Buchanan' },
        { resourceId: 8, resourceName: 'Jack Davolio' },
        { resourceId: 9, resourceName: 'Tamer Vinet' },
        { resourceId: 10, resourceName: 'Vinet Fuller' },
        { resourceId: 11, resourceName: 'Bergs Anton' },
        { resourceId: 12, resourceName: 'Construction Supervisor' }
    ];

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            treeColumnIndex={1}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            labelSettings={labelSettings}
            resourceFields={resourceFields}
            resources={resources}
            columns={columns}
        >
            <Inject services={[Selection]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Inject, Selection } from '@syncfusion/ej2-react-gantt';
import { TaskFieldsModel, ResourceFieldsModel, LabelSettingsModel } 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',
        dependency: 'Predecessor',
        resourceInfo: 'resources',
        parentID: 'ParentID'
    };

    const labelSettings: LabelSettingsModel = {
        leftLabel: 'TaskName',
        rightLabel: 'resources'
    };

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

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

    const projectStartDate = new Date('03/25/2019');
    const projectEndDate = new Date('07/28/2019');

    const resources: object[] = [
        { resourceId: 1, resourceName: 'Martin Tamer' },
        { resourceId: 2, resourceName: 'Rose Fuller' },
        { resourceId: 3, resourceName: 'Margaret Buchanan' },
        { resourceId: 4, resourceName: 'Fuller King' },
        { resourceId: 5, resourceName: 'Davolio Fuller' },
        { resourceId: 6, resourceName: 'Van Jack' },
        { resourceId: 7, resourceName: 'Fuller Buchanan' },
        { resourceId: 8, resourceName: 'Jack Davolio' },
        { resourceId: 9, resourceName: 'Tamer Vinet' },
        { resourceId: 10, resourceName: 'Vinet Fuller' },
        { resourceId: 11, resourceName: 'Bergs Anton' },
        { resourceId: 12, resourceName: 'Construction Supervisor' }
    ];

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            treeColumnIndex={1}
            projectStartDate={projectStartDate}
            projectEndDate={projectEndDate}
            labelSettings={labelSettings}
            resourceFields={resourceFields}
            resources={resources}
            columns={columns}
        >
            <Inject services={[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/33.1.44/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
</head>

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

</html>

Manage resource assignments

Add or remove resources via cell or dialog editing. Cell editing modifies assignments by double-clicking the resource cell, while dialog editing uses the resource tab in the edit dialog.

Resource cell editing
Alt text: Resource cell editing in the Gantt grid for assignment modifications.

Resource dialog editing
Alt text: Resource dialog editing tab for multiple allocations and units.

Customize resource styling

Customize resource display using column templates for the resource column and the queryTaskbarInfo event for taskbar styling based on assigned resources.

The following example demonstrates custom resource styling:

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

import { data, projectResources } from './datasource';

function App() {

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

    const splitterSettings = {
        columnIndex: 2
    };

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

    function getResourceStyle(name) {
        switch (name) {
            case 'Martin Tamer': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '81px', height: '24px', borderRadius: '24px', background: '#DFECFF' };
            case 'Rose Fuller': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '71px', height: '24px', borderRadius: '24px', background: '#E4E4E7' };
            case 'Margaret Buchanan': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '123px', height: '24px', borderRadius: '24px', background: '#DFFFE2' };
            case 'Tamer Vinet': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '75px', height: '24px', borderRadius: '24px', background: '#FFEBE9' };
            default: return {};
        }
    }

    function getResourceTextStyle(name) {
        switch (name) {
            case 'Martin Tamer': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#006AA6' };
            case 'Rose Fuller': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#766B7C' };
            case 'Margaret Buchanan': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#00A653' };
            case 'Tamer Vinet': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#FF3740' };
            default: return {};
        }
    }

    function resourceTemplate(props) {
        const names = props.ganttProperties.resourceNames;
        if (!names) return null;

        return (
            <div style={getResourceStyle(names)}>
                <div style={getResourceTextStyle(names)}>
                    {names}
                </div>
            </div>
        );
    }

    function queryTaskbarInfo(args) {
        const name = args.data.ganttProperties.resourceNames;
        if (!name) return;

        if (name === 'Martin Tamer') {
            args.taskbarBgColor = '#DFECFF';
            args.progressBarBgColor = '#006AA6';
        } else if (name === 'Rose Fuller') {
            args.taskbarBgColor = '#E4E4E7';
            args.progressBarBgColor = '#766B7C';
        } else if (name === 'Margaret Buchanan') {
            args.taskbarBgColor = '#DFFFE2';
            args.progressBarBgColor = '#00A653';
        } else if (name === 'Tamer Vinet') {
            args.taskbarBgColor = '#FFEBE9';
            args.progressBarBgColor = '#FF3740';
        }
    }

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            allowResizing={true}
            rowHeight={50}
            splitterSettings={splitterSettings}
            resourceFields={resourceFields}
            resources={projectResources}
            queryTaskbarInfo={queryTaskbarInfo}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskName" headerText="Task Name" width={270} />
                <ColumnDirective field="resources" headerText="Resources" width={175} template={resourceTemplate} />
                <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={[Resize, Selection]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
    GanttComponent,
    ColumnsDirective,
    ColumnDirective,
    Inject,
    Resize,
    Selection,
    TaskFieldsModel,
    ResourceFieldsModel,
    SplitterSettingsModel,
    IQueryTaskbarInfoEventArgs
} from '@syncfusion/ej2-react-gantt';

import { data, projectResources } from './datasource';

function App() {

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

    const splitterSettings: SplitterSettingsModel = {
        columnIndex: 2
    };

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

    function getResourceStyle(name: string): React.CSSProperties {
        switch (name) {
            case 'Martin Tamer': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '81px', height: '24px', borderRadius: '24px', background: '#DFECFF' };
            case 'Rose Fuller': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '71px', height: '24px', borderRadius: '24px', background: '#E4E4E7' };
            case 'Margaret Buchanan': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '123px', height: '24px', borderRadius: '24px', background: '#DFFFE2' };
            case 'Tamer Vinet': return { display: 'flex', padding: '1.5px 12px', gap: '10px', width: '75px', height: '24px', borderRadius: '24px', background: '#FFEBE9' };
            default: return {};
        }
    }

    function getResourceTextStyle(name: string): React.CSSProperties {
        switch (name) {
            case 'Martin Tamer': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#006AA6' };
            case 'Rose Fuller': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#766B7C' };
            case 'Margaret Buchanan': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#00A653' };
            case 'Tamer Vinet': return { width: '72px', height: '22px', fontWeight: 500, fontSize: '14px', lineHeight: '22px', textAlign: 'center', color: '#FF3740' };
            default: return {};
        }
    }

    function resourceTemplate(props: any) {
        const names = props.ganttProperties.resourceNames;
        if (!names) return null;

        return (
            <div style={getResourceStyle(names)}>
                <div style={getResourceTextStyle(names)}>
                    {names}
                </div>
            </div>
        );
    }

    function queryTaskbarInfo(args: IQueryTaskbarInfoEventArgs): void {
        const name = args.data.ganttProperties.resourceNames;
        if (!name) return;

        if (name === 'Martin Tamer') {
            args.taskbarBgColor = '#DFECFF';
            args.progressBarBgColor = '#006AA6';
        } else if (name === 'Rose Fuller') {
            args.taskbarBgColor = '#E4E4E7';
            args.progressBarBgColor = '#766B7C';
        } else if (name === 'Margaret Buchanan') {
            args.taskbarBgColor = '#DFFFE2';
            args.progressBarBgColor = '#00A653';
        } else if (name === 'Tamer Vinet') {
            args.taskbarBgColor = '#FFEBE9';
            args.progressBarBgColor = '#FF3740';
        }
    }

    return (
        <GanttComponent
            height="430px"
            dataSource={data}
            taskFields={taskFields}
            allowResizing={true}
            rowHeight={50}
            splitterSettings={splitterSettings}
            resourceFields={resourceFields}
            resources={projectResources}
            queryTaskbarInfo={queryTaskbarInfo}
        >
            <ColumnsDirective>
                <ColumnDirective field="TaskName" headerText="Task Name" width={270} />
                <ColumnDirective field="resources" headerText="Resources" width={175} template={resourceTemplate} />
                <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={[Resize, 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/33.1.44/tailwind3.css" rel="stylesheet" type="text/css" />
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
</head>

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

</html>

This configuration applies background colors to resource columns and taskbars, with the queryTaskbarInfo event modifying taskbar properties dynamically.

See also