Gantt timeline
ProA project timeline with draggable, resizable bars, dependency arrows that follow them, and animated zoom.
- Planning work across weeks or months where tasks depend on each other.
- Roadmaps that people reschedule by dragging, with undo and conflict warnings.
- Phase based plans where finished phases can be folded into a summary bar.
- Use project-board for status columns without dates.
- Use week-calendar for time slots within days.
- Use timeline for a read-only list of dated events.
Installation
Pro source and install commands unlock with a Pro plan.
Usage
Use this as a starting point and replace the sample data with your own.
"use client"; import { useState } from "react";import { GanttTimeline } from "@/components/arc/blocks/gantt-timeline/gantt-timeline";import type { GanttGroup, GanttTask } from "@/components/arc/blocks/gantt-timeline/gantt-timeline"; const groups: GanttGroup[] = [ { id: "design", name: "Design" }, { id: "build", name: "Build" },]; const initial: GanttTask[] = [ { id: "wires", name: "Wireframes", group: "design", start: "2026-10-05", end: "2026-10-09", progress: 1 }, { id: "ui", name: "Visual design", group: "design", start: "2026-10-12", end: "2026-10-23", progress: 0.4, dependsOn: ["wires"] }, { id: "api", name: "API", group: "build", start: "2026-10-12", end: "2026-10-30", progress: 0.2 }, { id: "beta", name: "Beta", group: "build", start: "2026-11-02", end: "2026-11-02", milestone: true, dependsOn: ["ui", "api"] },]; export function Roadmap() { const [tasks, setTasks] = useState(initial); return ( <GanttTimeline title="Q4 roadmap" groups={groups} defaultTasks={initial} tasks={tasks} onTasksChange={(next, change) => { setTasks(next); if (change.kind === "move" || change.kind === "resize") { void fetch("/api/tasks/" + change.id, { method: "PATCH", body: JSON.stringify({ start: change.start, end: change.end }) });API reference
4 parts. The first is the root.
GanttTimeline
A project timeline with tasks grouped by phase. Drag a bar to move it or its edges to change dates, snapped to whole days. Dependency arrows re-route as bars move and turn red when a task starts before one it depends on ends. Zoom glides between day, week, and month. Also the default export.
titlestring"App relaunch"Heading in the toolbar and the section's accessible name.groupsGanttGroup[]GROUPSPhases in display order. Each task's group field refers to a group id.tasksGanttTask[]–Controlled tasks. Pair with onTasksChange.defaultTasksGanttTask[]TASKSStarting tasks when uncontrolled. Also sets the calendar range once on mount and is what Reset restores.onTasksChange(tasks: GanttTask[], change: GanttChange) => void–Called after a move, resize, undo, or reset with the full list and what changed.todaystring"2026-09-23"ISO date that places the today line and the initial scroll.zoomGanttZoom–Controlled zoom: "day", "week", or "month".defaultZoomGanttZoom"week"Starting zoom when uncontrolled.onZoomChange(zoom: GanttZoom) => void–Called when the zoom control changes.collapsedstring[]–Controlled ids of folded groups.defaultCollapsedstring[]["discovery"]Groups folded on first render when uncontrolled.onCollapsedChange(ids: string[]) => void–Called when a group is folded or unfolded.classNamestring–Extra class on the root section.GanttTask
Exported type. { id: string; name: string; group: string; start: string; end: string; progress?: number; assignee?: PersonId; dependsOn?: string[]; milestone?: boolean }. Dates are ISO days and end is inclusive; a milestone uses start only. progress runs from 0 to 1.
No props.
GanttGroup
Exported type. { id: string; name: string }.
No props.
GanttChange
Exported type passed to onTasksChange. { id: string; start: string; end: string; kind: "move" | "resize" | "undo" | "reset" }.
No props.
- Tab
- Moves into the chart; one bar is tabbable at a time.
- Arrow DownorArrow Up
- Moves focus to the next or previous visible bar and scrolls it into view.
- Alt+Arrow LeftorRight
- Moves the focused task by one day.
- Alt+Shift+Arrow LeftorRight
- Changes the focused task's end date by one day.
- EnterorSpace
- Selects or deselects the focused bar, highlighting its dependency arrows.
- Escape
- Clears the selection.
- Bars are role="button" with aria-roledescription "Task bar" or "Milestone", aria-pressed for selection, and a label with name, dates, percent done, and a warning when a dependency is violated.
- Every bar is described by hidden text that explains the Alt and Alt Shift shortcuts.
- Folded rows are aria-hidden and inert; group toggles carry aria-expanded.
- The zoom control is a group of aria-pressed buttons. The footer status is role="status" and reports each change and conflict.
- The calendar header, grid lines, arrows, and summary bars are aria-hidden.
- Bars, arrows, group summaries, and task rows read the same motion values, so they move together without drifting.
- After a drag, the bar springs to the snapped day from its release velocity; a dashed snap target and a date label show while dragging.
- Shortening past one day resists with a soft rubber band instead of stopping.
- Zoom animates the day scale on a spring while keeping the middle of the view fixed; the header tiers crossfade.
- Folding a group slides its rows up into the group row and fades them.
- Reduced motion jumps bars, rows, scale, and scroll to their targets and removes the crossfades.
- When the scroller is under 560px wide, the sticky task column narrows from 248px to 132px.
- Bars under 96px wide hide their name and bars under 36px hide their percentage, through container queries on each bar.
- The chart scrolls horizontally, and dragging near either edge scrolls the view along with the bar.
- Below 480px viewport width the root padding and task row indent shrink.
- Drag, zoom, and row folding update motion values; React re-renders only on commit and when the snapped day changes.
- Each dependency arrow recomputes its path from motion values every frame while something moves; keep plans in the tens of tasks.
- The header and grid lines render one element per day at day zoom, so very long ranges add DOM weight.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for project plans with phases, dependencies, and drag to reschedule.
- The calendar range is computed once on mount from defaultTasks and today, starting on a Monday with a week before and three weeks after. In controlled mode pass defaultTasks as well, or the calendar spans the sample data.
- onTasksChange reports each move or resize as ISO start and end dates; persist change.id with those dates. Undo keeps the last 20 changes.
- Assignee avatars come from @/components/arc/lib/media PersonId portraits; tasks without one show a plain marker.
- Dependency conflicts are shown, not prevented. Validate on the server if a violation must be blocked.
The full library index for assistants is at /llms.txt.