Widgets
Gantt
A Gantt chart with dependencies and a critical path.
A Gantt chart: dated items as bars that can be moved and stretched by their edges. Dependencies are drawn as arrows, and the critical path is highlighted.
Installation
npx @toimetdev/pathlogs-ui add ganttExample
<Gantt
items={tasks}
edges={links.filter((l) => l.type === "BLOCKS")}
locale="en-US"
renderLabel={(task) => (
<>
<span className="font-mono text-[11px] text-muted">UI-{task.number}</span>
<span className="truncate">{task.title}</span>
</>
)}
barColor={(task) => STATUS_COLORS[task.status]}
onChangeDates={(id, dates) => updateTaskAction(id, dates)}
onOpenItem={(task) => router.push(`/tasks/${task.id}`)}
/>Drag a bar whole or by its edge. The canvas pans on both axes, arrows scroll, and Home and End jump to the ends.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items* | I[] | — | The items. They need id, startDate and dueDate — strings like 2026-02-14. |
renderLabel* | (item: I) => ReactNode | — | The row's caption in the left-hand column. |
edges | { fromId, toId }[] | [] | «from blocks to» links: arrows and the critical path. |
onChangeDates | (itemId, { startDate, dueDate }) => void | Promise | — | The new dates after a drag. Without it the chart is read-only. |
onOpenItem | (item: I) => void | — | A click on a bar. |
barColor | (item: I) => string | — | The bar colour — usually by status. Overridden by the item.color field. |
locale | string | — | The locale for the scale's captions. Defaults to the browser's locale. |
labels | GanttLabels | — | Captions. English by default. |
items*I[]The items. They need id, startDate and dueDate — strings like 2026-02-14.
renderLabel*(item: I) => ReactNodeThe row's caption in the left-hand column.
edges{ fromId, toId }[]defaults to: []
«from blocks to» links: arrows and the critical path.
onChangeDates(itemId, { startDate, dueDate }) => void | PromiseThe new dates after a drag. Without it the chart is read-only.
onOpenItem(item: I) => voidA click on a bar.
barColor(item: I) => stringThe bar colour — usually by status. Overridden by the item.color field.
localestringThe locale for the scale's captions. Defaults to the browser's locale.
labelsGanttLabelsCaptions. English by default.
The critical path
The chain of dependencies that is longest by total duration. Highlighted in amber — both the bars themselves and the arrows between them.
A single item does not count as a path either: «a critical path of one task» says nothing about the plan.
Dragging
- A whole bar moves both ends, preserving its duration.
- The edges move only their own end and stop against the opposite one — you cannot turn a bar inside out and get a due date before the start.
- The offset is rounded to a day. A bar lands on a whole day, not between days.
- A zero offset saves nothing — that was a click, not a drag.
The layout, separately
import {
datedRows, // what makes it onto the chart at all, in start order
buildScale, // the date scale: day width chosen from the plan's length
layoutBars, // the position of each bar
criticalPath, // the longest chain of dependencies
applyDrag, // the dates after a drag
toISODate,
} from "@/components/ui/gantt/ganttLayout";The day width is chosen automatically: 32px for plans up to a month and a half, 20px up to three months, and 12px beyond that. Over a yearly horizon, 32px per day would give you a canvas impossible to scroll through.