Creating tasks
Let people add a task from the chart, then turn the draft it hands you into a row.
Task creation stops at a draft. The chart collects a date range from a button, a drawn range or the chart ref, then calls onTaskCreate and adds no row itself.
Turn on task creation
Pass onTaskCreate and add the new task to your own state. Without that callback there is no button, no crosshair cursor and no drawing gesture.
import { useState } from 'react';
import { ReactGanttChart, type GanttTaskDraft, type Task } from '@jaeungkim/gantt-chart';
import '@jaeungkim/gantt-chart/style.css';
const initialTasks: Task[] = [
{ id: 'design', name: 'Design', parentId: null, sequence: '1',
startDate: '2026-09-01', endDate: '2026-09-08' },
];
export function ProjectChart() {
const [tasks, setTasks] = useState<Task[]>(initialTasks);
const handleTaskCreate = ({ startDate, endDate }: GanttTaskDraft) => {
setTasks((current) => [
...current,
{
id: crypto.randomUUID(),
name: 'New task',
startDate,
endDate,
parentId: null,
sequence: `${current.length + 1}`,
},
]);
};
return (
<ReactGanttChart
tasks={tasks}
onTasksChange={setTasks}
onTaskCreate={handleTaskCreate}
showTaskList
height={420}
/>
);
}The draft carries startDate and endDate and nothing else, UTC ISO strings snapped to the current scale. It names no row, so your app sets the id, the name, parentId and sequence. See Task data.
onTasksChange does not fire for a draft. The new row appears once your state holds the task.
Where a draft comes from
Three entry points produce the same draft.
The Add task button sits at the foot of the task list, so it needs showTaskList. A click sends a draft one tick long at today, or at the first tick when today falls outside the rendered timeline.
addTask() on the chart ref sends that same draft from your own toolbar or keyboard shortcut. See Imperative API.
A drawn range starts below the last row. Press in the blank space there, drag sideways and release. A press on a row draws nothing, whether it lands on a bar, an arrow, a handle or the row's empty part.
A mouse starts drawing at once. Touch and pen need the same 400 ms hold as a bar drag, described in Editing tasks. Vertical movement is ignored. A drag shorter than 4px sends nothing, and Escape cancels a draw in progress.
Snap to the current scale
A drawn range expands outwards to whole ticks of the scale on screen. The timeline lists what one tick holds at each scale.
A range that stays inside one tick comes out one tick long.
A bar drag uses a different step. On the month scale a bar moves in 1-day steps while a drawn range comes out in whole weeks.
minDate and maxDate are not applied to a drawn range, so a draft can start before minDate. See Editing tasks.
Turn creation off
allowTaskCreate is chart-wide and governs all three entry points. Set it to false and the button is not rendered, the drawing gesture is off and addTask() does nothing.
With allowTaskCreate omitted, creation follows readOnly. Task has no allowTaskCreate field, so a value set there is ignored. See interaction configuration.
Before you integrate
onTaskCreateis what enables creation.allowTaskCreateon its own renders no button and arms no gesture.visibleStartandvisibleEndgive an empty chart a timeline. With no tasks and no pinned window there are no ticks to snap a range to, so no entry point produces a draft.- The drawing gesture needs a pointer. The Add task button is the keyboard path to the same draft and takes its own tab stop after the rows. No key is bound to creation. See Keyboard and screen readers.
- Deletion has no pointer path. A task is removed from the keyboard.
See GanttProps for prop definitions and Task list and hierarchy for the pane the button sits in.