Gantt

App

MS Project / GanttPRO / dhtmlxGantt-style project timeline. M1 ships the scale switcher (day / week / month / quarter / year), a vertical Today line, WBS tree with expand/collapse on the left panel, sticky timeline header with synchronised horizontal + vertical scroll, and absolutely-positioned task bars with a %-progress fill. M2 adds full interactivity: drag a bar to reschedule (snap to day), drag the left/right edges to resize, drag the white progress thumb to change %, and drag from the right-edge blue dot to another bar to draw an FS dependency. Dependencies render as orthogonal SVG arrows with a marker-end arrowhead; click an arrow then press Delete to remove it. M3 adds a Critical Path toggle in the toolbar — tasks on the longest dependency chain switch to var(--error) styling and their connecting arrows turn red, computed by a forward + backward longest-path pass on the dependency DAG. Hovering a bar after a short delay shows a tooltip with name, start/end, duration, owner, % complete, predecessors, and a Critical badge. M4 adds zero-duration milestones rendered as 14×14 diamonds, planned-vs-actual baseline ghost bars beneath the live bars, and weekend + holiday shading on the day + week scales. M5 adds a toolbar Export menu (PNG via SVG `<foreignObject>` round-trip, PDF via the browser print dialog, CSV via a pure-JS Blob download), drag snap that nudges drops forward to the next working day, and a resource-conflict detector that flags over-allocated owners in the WBS panel with a red triangle. M6 closes the loop with grid keyboard navigation (↑↓/Home/End/PageUp/PageDown between rows, +/− zoom, focused bar exposes a focus ring + `aria-activedescendant`), a `locale` prop that drives Intl-based month names and tooltip dates, `prefers-reduced-motion` honouring (plus a `reducedMotion` prop force-on), and automatic row virtualization above ~60 tasks. All mutations are optimistic and roll back automatically if `onTaskUpdate` / `onDependencyCreate` rejects. Internal state is owned by a per-instance Zustand store (`store.ts`).

Week scale (default)

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
<Gantt tasks={tasks} scale="week" ariaLabel="Product launch plan" />

Month scale

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
Jun2026
Jul2026
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
<Gantt tasks={tasks} scale="month" ariaLabel="Long-range roadmap" />

Collapsed group

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Release
Staging deploy0%
Code
// Seed any task with `collapsed: true` to hide its children at first paint.
const tasks = base.map((t) => t.id === 'impl' ? { ...t, collapsed: true } : t);
<Gantt tasks={tasks} scale="week" />

Dependencies (FS + SS)

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
const dependencies = [
  { id: 'd-t1-t2', from: 't1', to: 't2', type: 'FS' }, // Finish-to-Start
  { id: 'd-t4-t5', from: 't4', to: 't5', type: 'SS' }, // Start-to-Start
];

<Gantt tasks={tasks} dependencies={dependencies} scale="week" />

Critical path (CPM)

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
// Critical-path highlight uses a forward + backward longest-path pass
// over the dependency DAG. Tasks with zero float switch to error styling
// and their connecting arrows turn red. The toolbar toggle lets users
// switch it on / off; passing the prop sets the initial value.
<Gantt
  tasks={tasks}
  dependencies={dependencies}
  scale="week"
  criticalPath
/>

Milestones + baselines + weekends

Preview

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
// Milestones (zero-duration tasks rendered as diamonds), planned-vs-actual
// baseline ghost bars, and weekend / holiday shading on the day + week scales.
const baselines: Baseline[] = [
  { taskId: 't2', start: new Date('2026-05-01'), end: new Date('2026-05-07') },
  { taskId: 't5', start: new Date('2026-05-10'), end: new Date('2026-05-20') },
];

<Gantt
  tasks={tasks}                // include some { isMilestone: true } entries
  dependencies={dependencies}
  baselines={baselines}
  workingDays={[1, 2, 3, 4, 5]} // Mon-Fri; Sat+Sun shaded
  holidays={[new Date('2026-05-05')]}
  scale="week"
/>

Export + resource conflicts + working-day snap

Preview

Eve M. is double-booked across three tasks (red ⚠ in the owner column). Use Export in the toolbar to download a CSV of the plan or open the print dialog to save as PDF. Drag a bar onto a weekend withworkingDays set and it snaps forward to Monday.

Today: 6/24/2026

Export
TaskOwner%
Frontend rebuild
Eve M.40%
Auth migration
Eve M.20%
Reporting dashboard
Eve M.0%
Design system bump
Ada L.50%
Launch
PM0%
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Frontend rebuild40%
Auth migration20%
Reporting dashboard0%
Design system bump50%
Code
// M5 wires three things at once:
//  1. exportFormats opens the toolbar Export menu (PNG / PDF / CSV).
//  2. Tasks sharing an owner that overlap in time get a red ⚠ in the WBS
//     owner column (resource over-allocation).
//  3. workingDays makes drag snap forward to the next working day, so a
//     drop on a weekend lands on Monday.
const tasks: Task[] = [
  { id: 'r1', name: 'Frontend rebuild', start: ..., end: ..., owner: 'Eve M.' },
  { id: 'r2', name: 'Auth migration',   start: ..., end: ..., owner: 'Eve M.' }, // overlaps r1
  { id: 'r3', name: 'Reporting',        start: ..., end: ..., owner: 'Eve M.' }, // overlaps r2
];

<Gantt
  tasks={tasks}
  workingDays={[1, 2, 3, 4, 5]}
  exportFormats={['png', 'pdf', 'csv']}
  scale="week"
/>

Keyboard nav + locale + reduced motion

Preview

Click the chart, then use to step between rows, Home / End to jump to first / last, PgUp / PgDn to page 5 rows, and + / to zoom in / out. Headers and tooltip dates render in Turkish via the locale prop.

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Haz 1
W24Haz 8
W25Haz 15
W26Haz 22
W27Haz 29
W28Tem 6
W29Tem 13
W30Tem 20
W31Tem 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
// M6 adds:
//  - Grid keyboard nav from the Gantt root: ↑↓ between rows, Home/End,
//    PageUp/PageDown (5 rows), and +/− to zoom in/out. Focused bar gets a
//    border-focus ring and is announced via aria-activedescendant.
//  - locale prop drives Intl.DateTimeFormat for month names in the header
//    and date formatting in the hover tooltip.
//  - reducedMotion={true} or the OS prefers-reduced-motion media query
//    suppresses every Tailwind transition/animation under the root.
//  - Row virtualization kicks in automatically above ~60 tasks — only the
//    visible ± buffer slice renders, so 1000+ rows stay smooth.
<Gantt
  tasks={tasks}
  dependencies={deps}
  locale="tr-TR"               // Turkish month names / tooltip dates
  reducedMotion                // optional — force motion off
  scale="week"
/>

Interactive (drag + dependencies)

Preview

Drag a bar to reschedule, drag its edges to resize, drag the white thumb to change progress, or drag from the blue dot on a bar's right edge to another bar to add a dependency. Click a dependency arrow and press Delete to remove it.

Today: 6/24/2026

TaskOwner%
Design phase
Ada L.70%
Wireframes
Ada L.100%
Visual design
Jane D.80%
Design review
Team20%
Implementation
John S.35%
Frontend skeleton
John S.50%
API integration
Mira K.25%
End-to-end tests
QA0%
Release
PM0%
Staging deploy
DevOps0%
Launch
PM0%
W23Jun 1
W24Jun 8
W25Jun 15
W26Jun 22
W27Jun 29
W28Jul 6
W29Jul 13
W30Jul 20
W31Jul 27
Design phase
Wireframes100%
Visual design80%
Design review20%
Implementation
Frontend skeleton50%
API integration25%
End-to-end tests0%
Release
Staging deploy0%
Code
const [tasks, setTasks] = useState<Task[]>(initial);
const [deps,  setDeps]  = useState<Dependency[]>([]);

<Gantt
  tasks={tasks}
  dependencies={deps}
  scale="week"
  onTaskUpdate={(t) => setTasks((prev) => prev.map((p) => (p.id === t.id ? t : p)))}
  onDependencyCreate={(d) => setDeps((prev) => [...prev, d])}
  onDependencyDelete={(id) => setDeps((prev) => prev.filter((d) => d.id !== id))}
/>
Sourcemodules/app/Gantt/index.tsx