React Gantt Chart

Bars on a calendar are a picture; bars plus dependencies are a schedule. Rows are resources, bars are jobs, and the arrows show what has to finish before what can start — so when one job slips you can see exactly what slips with it.

Lot L2411 — process schedule

Day 0 = Mon 20 Jul · 16 days

DoneRunningPlannedLate
D0D1D2D3D4D5D6D7D8D9D10D11D12D13D14D15LithoEtchImplantCMPTestMask prepExpose L1Expose L2Etch L1Etch L2ImplantAnnealCMPProbe testnow

Installation

npx shadcn@latest add "https://kelvinui.com/registry/gantt-chart.json"

Props

PropTypeDescription
tasksGanttTask[]{ id, label, resource, start, end, progress?, status?, dependsOn? }
daysnumberTotal days on the axis
originLabelstringWhat day 0 means, e.g. "Mon 20 Jul"
nownumberPosition of the now marker, in days
titlestringHeading

Days, not dates

start and end are day offsets from the origin, not Date objects — deliberately. Dates in a statically exported app drag in timezone and locale differences between the server and the browser, which is exactly the class of hydration bug this library avoids elsewhere. Keep the arithmetic in plain numbers and put the human date in originLabel.

Rows are derived from resource in first-appearance order, so a task's row is wherever you put its resource in the array. Dependencies render as finish-to-start elbows with an arrowhead, routed around the bars; hovering either end of a link lights the whole chain, which is how you trace a slip. status is done, running, planned, or late — and late exists as its own status rather than being inferred from now, because "should have started" and "is behind" are judgements your scheduler makes, not the chart.

New components every week

Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.