JavaScript Gantt chart
A JavaScript Gantt chart you can drop into any app
GanttKit is a JavaScript Gantt chart library built as a headless engine plus a renderer. Install two packages, point createGantt at an element, and you have a scrollable, draggable timeline. No framework, no global registration, no config file.
Plain JavaScript 0 core dependencies ESM + CJS Tree-shakeable SSR-safe core MIT
Install the npm packages
Every package lives under the @ganttkit scope on npm. You always need the core plus one renderer. Feature plugins are separate packages, so an unused feature costs nothing in your bundle.
# core + the SVG renderer
npm i @ganttkit/core @ganttkit/svg
# or the HTML renderer, or canvas for very large datasets
npm i @ganttkit/core @ganttkit/html
npm i @ganttkit/core @ganttkit/canvas
# add only the features you use
npm i @ganttkit/plugin-columns @ganttkit/plugin-tree @ganttkit/plugin-progress
The core has zero runtime dependencies, so the npm install adds no transitive tree of its own. Packages ship both ESM and CommonJS builds with TypeScript definitions included.
Render your first chart
createGantt builds the engine and installs the renderer in one call. The target element only needs a height; the chart fills it and scrolls internally.
import { createGantt } from '@ganttkit/svg'
import '@ganttkit/svg/styles.css'
const gantt = createGantt({
target: '#chart', // selector or HTMLElement
theme: 'dark', // 'dark' | 'light'
viewMode: 'Week', // 'Day' | 'Week' | 'Month'
rows: [
{
id: 'design',
name: 'Design',
tasks: [
{ id: 't1', name: 'Wireframes', start: '2026-07-01', end: '2026-07-08', progress: 1 },
{ id: 't2', name: 'Mockups', start: '2026-07-09', end: '2026-07-20', progress: 0.4 },
],
},
{
id: 'build',
name: 'Development',
tasks: [
{ id: 't3', name: 'API', start: '2026-07-15', end: '2026-08-05', progress: 0.2 },
{ id: 'ms', name: 'Launch', start: '2026-08-31', end: '2026-08-31', kind: 'milestone' },
],
},
],
})
<div id="chart" style="height: 480px"></div>
The data model
A chart is an array of rows; each row owns an array of tasks. Dates are ISO strings or Date objects, parsed by a replaceable date adapter.
| Field | Type | Notes |
|---|
id | string | Required, unique. Dependencies reference task ids. |
name | string | Rendered as the bar label and the default sidebar column. |
start, end | string | Date | Required on tasks. end is inclusive, so a same-day task is one day wide. |
kind | 'task' | 'milestone' | Optional. A milestone renders as a diamond at end. |
progress | number | Optional, 0 to 1. Drawn by the progress plugin. |
dependencies | string[] | Optional predecessor task ids, finish-to-start. |
Compose plugins instead of toggling options
When you need more than bars, build the engine yourself and install plugins with use(). The engine is chainable and recomputes after every install. The same plugin array works with any renderer, so switching from SVG to Canvas is an import change.
import { GanttEngine } from '@ganttkit/core'
import { svgRenderer } from '@ganttkit/svg'
import { createColumns } from '@ganttkit/plugin-columns'
import { createTree } from '@ganttkit/plugin-tree'
import { progressPlugin } from '@ganttkit/plugin-progress'
import '@ganttkit/svg/styles.css'
const engine = new GanttEngine({ rows, viewMode: 'Week' })
engine.use(svgRenderer({ target: '#chart', theme: 'dark' }))
engine.use(createColumns({ columns: [{ key: 'name', label: 'Task' }] }).plugin)
engine.use(createTree().plugin)
engine.use(progressPlugin())
Update the chart at runtime
The engine is the source of truth. Mutating methods recompute the pipeline and the renderer repaints from the new scene.
gantt.setRows(nextRows) // replace the dataset
gantt.updateTask('t2', { progress: 0.8 }) // patch one task
gantt.updateTaskDates('t3', '2026-07-20', '2026-08-12') // move or resize
gantt.setViewMode('Month') // zoom out
gantt.destroy() // remove listeners, dispose plugins
Drag to move and drag to resize are enabled by default. Turn them off globally with the draggable option, or per task with draggable: false on the task itself.
Bundle behavior
- Tree-shakeable. Plugins are separate entry points; a plugin you never import is never bundled.
- ESM and CJS. Both builds are published, so bundlers and Node both resolve cleanly.
- SSR-safe core. The engine touches no DOM and no browser globals, so it computes on the server. Only the renderer needs a document.
- Virtualized. A 20,000 task chart emits about 80 vector nodes; scroll rebuilds run in under a millisecond.
Keep reading
Frequently asked questions
Which npm package do I install for a JavaScript Gantt chart?
Install @ganttkit/core together with a renderer: @ganttkit/svg, @ganttkit/html or @ganttkit/canvas. Feature plugins such as @ganttkit/plugin-columns are separate packages, so you only add the ones you use.
Does the JavaScript Gantt chart work without a framework?
createGantt takes a CSS selector or an HTMLElement and mounts into it. There is no framework dependency in the core or the renderers, so plain JavaScript with a bundler is enough.
How do I update tasks after the chart is rendered?
Call setRows to replace the dataset, updateTask to patch a single task, or updateTaskDates to move one. The engine recomputes and the renderer repaints the affected part of the scene.
Does it support drag to reschedule?
Dragging is on by default and can be disabled globally with the draggable option or per task. With the dependencies plugin installed, moving a predecessor shifts its dependents.