The React Gantt chart displays a project schedule as task rows and a horizontal timeline. Show task hierarchies, milestones, dependencies, and progress, and let users adjust task dates directly.

This component is included in DayPilot Pro for JavaScript. It is not included in DayPilot Lite.

React Gantt Chart Component (DayPilot)

React Gantt Features

  • Task rows and groups. Each task has its own row and date range. Put related tasks in a children array to form a task hierarchy. A group bar spans its children, and expanding or collapsing the row switches between the group summary and individual tasks.

  • Progress and milestones. Supply complete to display a percentage and progress bar. A milestone marks one date; the introductory example ends with a release milestone after Planning and Implementation.

  • Dependency endpoints. A link identifies two tasks and the endpoints it connects. A finish-to-start link runs from the predecessor's end to the successor's start; other link types connect their start or finish points differently. Your application supplies any rules for changing related task dates.

  • Editing on the timeline. Move a task to change its dates, or resize it to change its duration. The examples below use the automatic update behavior and then save the changed record in a callback.

  • Details beside the task bar. Row-header columns can display task fields or formatted values. Choose the timeline range and scale independently, and use image export to capture the chart.

Show Progress and Duration Beside Each Task

The React Gantt example displays Name, Complete, and Duration columns. The Name column reads the task's text field directly. An onBeforeRowHeaderRender callback adds the percent sign to complete and formats task.duration().totalDays() as a number of days. It leaves those two cells empty for milestones. Try the live chart.

In the sample, Task 1 lasts two days and is 60% complete. Its parent, Group 101, spans six days and has a separately supplied completion value of 35%. The date span follows the child schedule; the progress value comes from the task data. Expand or collapse the group to see how the same columns align with task and summary rows.

This combines direct field mapping with calculated cell content. Use the same column mechanisms for the fields in your own task records. The introductory integration below starts with three rows; the linked project adds nested tasks, row creation, and interactive dependency links.

Demos and Tutorials

Each tutorial includes a downloadable project. The edition used by the example is shown beside its link.

React Gantt Project

Configure a Starter Project

Use Gantt UI Builder to explore settings in a live preview and download a React starter. Continue adjusting the generated configuration in your own code.

Installation

DayPilot Pro

At npm.daypilot.org, select React and copy the installation command for daypilot-pro-react. Licensed customers can obtain their package URL in the customer area.

The examples use JavaScript/JSX and function components with React 18 or later.

Display a Project with Dependencies

This project has a planning task, an implementation task and a release milestone. The links show the order of the work.

Gantt.jsx

import {useState} from 'react';
import {DayPilot, DayPilotGantt} from 'daypilot-pro-react';

export default function Gantt() {
  const [tasks] = useState([
    {id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
    {id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
    {id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
  ]);

  const [links] = useState([
    {id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
    {id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
  ]);

  return <DayPilotGantt
    startDate="2026-10-01"
    days={31}
    scale="Day"
    timeHeaders={[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]}
    tasks={tasks}
    links={links}
  />;
}

A task has a unique id, display text, and start/end dates. Ends are exclusive: Planning occupies October 5–7. A milestone uses type: "Milestone" and a start date. Each link connects two task IDs; FinishToStart connects the predecessor’s finish to the successor’s start.

See task loading for data formats and loading options.

Dependency links visualize relationships. The application decides how related tasks should be rescheduled and stores any link changes. Use task groups to organize a larger project into a hierarchy.

Load Tasks and Links Together

Load a project as {tasks: [...], links: [...]}. Assign both collections from the same response so that every dependency refers to a task in that project.

GanttLoading.jsx

import {useState, useEffect} from 'react';
import {DayPilot, DayPilotGantt} from 'daypilot-pro-react';

export default function Gantt() {
  const [tasks, setTasks] = useState([]);

  const [links, setLinks] = useState([]);

  useEffect(() => {
    let active = true;
    const url = '/api/projects/1';
    async function load() {
      try {
        const {data} = await DayPilot.Http.get(url);
        if (!active) { return; }
        setTasks(data.tasks);
        setLinks(data.links);
      } catch {
        if (active) { await DayPilot.Modal.alert('Could not load data.'); }
      }
    }
    load();
    return () => { active = false; };
  }, []);

  return <DayPilotGantt
    startDate="2026-10-01"
    days={31}
    scale="Day"
    timeHeaders={[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]}
    tasks={tasks}
    links={links}
  />;
}

The /api/projects/1 URL represents your own backend. Failed requests display a DayPilot dialog.

Move, Resize and Save Tasks

Moving changes the task position; resizing changes its duration. Both work in the first example without extra configuration. The component updates the display and the supplied data object automatically.

Use the callbacks after the edit to persist the result. This example sends the changed record to the backend; it does not reload the collection after each drag.

GanttSaving.jsx

import {useState} from 'react';
import {DayPilot, DayPilotGantt} from 'daypilot-pro-react';

export default function Gantt() {
  const [tasks] = useState([
    {id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
    {id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
    {id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
  ]);

  const [links] = useState([
    {id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
    {id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
  ]);

  async function saveTask(data) {
    try {
      await DayPilot.Http.put(`/api/tasks/${data.id}`, data);
    } catch {
      await DayPilot.Modal.alert('The change could not be saved.');
    }
  }

  return <DayPilotGantt
    startDate="2026-10-01"
    days={31}
    scale="Day"
    timeHeaders={[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]}
    tasks={tasks}
    links={links}
    onTaskMoved={args => saveTask(args.task.data)}
    onTaskResized={args => saveTask(args.task.data)}
  />;
}

The /api/tasks/{id} endpoint accepts the updated JSON record. A failed save is reported while the local edit remains visible; add retry or rollback behavior to suit your application. To disable an interaction, set taskMoveHandling or taskResizeHandling to "Disabled".

Handle a Task Click

To display the clicked item’s name, add this prop to the existing component:

onTaskClick={args => DayPilot.Modal.alert(DayPilot.Util.escapeHtml(args.task.text()))}

DayPilot.Modal.alert() accepts HTML. escapeHtml() displays the item’s name as plain text.

Access the Gantt API

Find the release milestone by ID and scroll the timeline to its start. This is useful when a booking or task lies outside the current horizontal viewport.

GanttApi.jsx

import {useState} from 'react';
import {DayPilot, DayPilotGantt} from 'daypilot-pro-react';

export default function Gantt() {
  const [gantt, setGantt] = useState(null);

  const [tasks] = useState([
    {id: 'planning', text: 'Planning', start: '2026-10-05', end: '2026-10-08'},
    {id: 'implementation', text: 'Implementation', start: '2026-10-08', end: '2026-10-20'},
    {id: 'release', text: 'Release', type: 'Milestone', start: '2026-10-20'}
  ]);

  const [links] = useState([
    {id: 'L1', from: 'planning', to: 'implementation', type: 'FinishToStart'},
    {id: 'L2', from: 'implementation', to: 'release', type: 'FinishToStart'}
  ]);

  function showRelease() {
    const control = gantt;
    const task = control.tasks.find('release');
    control.scrollTo(task.start());
  }

  return <>
    <button disabled={!gantt} onClick={showRelease}>Show release</button>
    <DayPilotGantt
      startDate="2026-10-01"
      days={31}
      scale="Day"
      timeHeaders={[{groupBy: 'Month'}, {groupBy: 'Day', format: 'd'}]}
      tasks={tasks}
      links={links}
      controlRef={setGantt}
    />
  </>;
}

React receives the underlying control through controlRef. The wrapper creates and disposes it. See the DayPilot.Gantt API for methods, properties and callbacks.

Use Next.js

Place the introductory component in Gantt.jsx and add 'use client'; at the top. Create a client wrapper that loads it with server rendering disabled:

GanttClient.jsx

'use client';

import dynamic from 'next/dynamic';

const Gantt = dynamic(() => import('./Gantt'), {ssr: false});

export default function GanttClient() {
  return <Gantt />;
}

Import GanttClient in your page and render <GanttClient />. The Next.js client wrapper keeps the DayPilot component in the browser. The tutorials above provide complete project setups.

Availability

Availability of this feature in DayPilot editions:

ProductLitePro
DayPilot for JavaScript
DayPilot for ASP.NET WebForms
DayPilot for ASP.NET MVC
DayPilot for Java