A task plan on a time axis. The task list is a WAI-ARIA treegrid that holds everything: WBS number, dates, duration, progress and predecessors, all editable inline. Beside it are bars, summary brackets, milestones, finish-to-start links, a today marker and non-working days. Drag a bar to move it, pull its end to resize, or drag its handle onto another bar to link them. Successors are auto-scheduled on working days.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Gantt } from "@vamos-ui/react/scheduler";
import { trWorkCalendar } from "@vamos-ui/react/locale-data";
<Gantt
tasks={tasks} // { id, parentId?, title, start, end (YYYY-MM-DD, inclusive), progress?, type? }
links={links} // { id, from, to, type: "FS", lagDays? }
defaultScale="week"
workCalendar={trWorkCalendar}
onTaskChange={(batch) => api.tasks.updateMany(batch)} // the task + every pushed successor
onLinkCreate={(l) => api.links.create(l)}
/>
// Scheduling without React (server, worker)
import { scheduleForward, detectCycles } from "@vamos-ui/react/scheduler";The treegrid is the accessible source of truth, and the timeline is aria-hidden. Use ↑/↓ for rows, ←/→ for cells (on the first cell, ← and → collapse and expand), Home and End, and Enter or F2 to edit a cell. Enter saves and Escape cancels. Date edits are the non-drag path (WCAG 2.5.7).
Bars are opaque colour mixes with no blur. The timeline sits on one surface.
The first release has finish-to-start links only. Critical path, baselines and RTL timeline mirroring come later.
Examples
Dependencies and auto-scheduling
A partner launch plan on trWorkCalendar. Move a task and its finish-to-start successors move with it, on working days only (29 October is skipped). Edit the Predecessors cell (“1.2, 3”) to add or remove links. A link that would create a loop is refused.
Zoom levels
A hiring timeline at day, week, month and quarter zoom. Week numbers follow the locale's rules (W46). Overdue tasks (unfinished and past today) get a red edge.
Client portal (read-only)
readOnly and scales={[]}: a calm progress view for clients, with no handles and no editing.
2,000 rows
400 work packages × 5 phases. Rows are virtualized from 150 (virtualizeAt), in the task list and the timeline together.
API
Gantt
| Prop | Type | Default |
|---|---|---|
tasks{ id, parentId?, title, start, end, progress? (0–1), type?: "task" | "milestone" | "summary", assignees?, tone?, editable? }. Parents span their children automatically. | GanttTask[] | — |
links{ id, from, to, type?: "FS", lagDays? }. This release draws and schedules finish-to-start links. | GanttLink[] | — |
scale / defaultScale / onScaleChangeZoom level. | "day" | "week" | "month" | "quarter" | "week" |
scalesZoom options in the toolbar. [] hides the switch. | GanttScale[] | all four |
workCalendarWorking days for durations, scheduling and the shaded non-working days (day zoom). | WorkCalendar | from locale |
durationUnitHow durations are counted and shown (“6 working days”). | "workdays" | "days" | "workdays" |
onTaskChangeOne batch per edit, including successors that moved. Applied at once; reject to revert. | (changes: { id, start, end, progress? }[]) => void | Promise<void> | — |
onLinkCreate / onLinkDeleteFrom dragging the connect handle onto another bar, clicking a link, or the Predecessors cell. Delete offers Undo. | (link) => void | Promise / (id) => void | Promise | — |
autoSchedulePush successors later when a task moves (never pulls them earlier). | boolean | true |
readOnlyNo drag, no inline editing. | boolean | false |
columnsTask-list columns: title, assignees, start, end, duration, progress, predecessors. | GanttColumnKey[] | ["title", "start", "end", "duration", "progress"] |
gridWidth / defaultGridWidth / onGridWidthChangeTask-list width. Drag the splitter, or focus it and use ←/→. | number (px) | — |
collapsed / defaultCollapsed / onCollapsedChangeIds of collapsed parent rows. | string[] | — |
height / rowHeight / virtualizeAtScroll height, row height (follows density by default), and the row count from which rows are virtualized. | string | number / number / number | "32rem" / density / 150 |
todaySets the today marker and the overdue state. | string (YYYY-MM-DD) | today in the locale zone |
toolbarExtra toolbar content. | ReactNode | — |
labelsOverrides for the gantt namespace strings. | Partial<GanttLabels> | — |
core (React-free)
| Prop | Type | Default |
|---|---|---|
scheduleForward(tasks, links, cal?, unit?)Pushes FS successors after their predecessors, working-day aware. Unchanged tasks keep their identity. | GanttTask[] | — |
detectCycles(links) / createsCycle(links, from, to)Dependency loop checks. | string[][] / boolean | — |
rollupSummaries / flattenTasks / visibleTasksParent spans and progress, WBS numbering, collapsed views. | functions | — |
taskDuration / moveTaskTo / linkViolationsWorking-day durations, moves that keep length, FS links that are violated. | functions | — |