Trend / Intermediate
Gantt Chart
Compare task dates, durations, and overlaps on a calendar timeline.
Interactive Chart Preview
JAVASCRIPTEdit the column names and values to update your chart. Changes stay in this page until you reload.
| Row# | Unique Task ID | Task Name | Start Date (Inclusive) | End Date (Exclusive) | Calculated Calendar Days | Remove row |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | ||||||
| 3 | ||||||
| 4 | ||||||
| 5 |
Give each task a unique ID. End must be after Start and is excluded from the duration: 6 to 9 January is three days. Weekends count. Overlapping tasks and repeated task names are valid.
Chart.js Code Example
JAVASCRIPTimport Chart from 'chart.js/auto';
// Illustrative data used by the live preview.
const chartData = {
"taskHeaders": [
"Task ID",
"Task",
"Start",
"End (Exclusive)",
"Duration (Days)"
],
"tasks": [
{
"id": "T1",
"label": "Requirements",
"start": "2025-01-06",
"end": "2025-01-09"
},
{
"id": "T2",
"label": "Design",
"start": "2025-01-08",
"end": "2025-01-13"
},
{
"id": "T3",
"label": "Build",
"start": "2025-01-13",
"end": "2025-01-20"
},
{
"id": "T4",
"label": "Review",
"start": "2025-01-17",
"end": "2025-01-22"
},
{
"id": "T5",
"label": "Release",
"start": "2025-01-22",
"end": "2025-01-23"
}
],
"datasets": []
};
function createConfig(chartData) {
const rows = chartData.tasks, headers = chartData.taskHeaders, day = 86400000;
const utc = (date) => Date.parse(`${date}T00:00:00.000Z`);
const starts = rows.map(row => utc(row.start)), ends = rows.map(row => utc(row.end));
const minimum = Math.min(...starts), maximum = Math.max(...ends);
const step = Math.max(1, Math.ceil((maximum - minimum) / day / 4)) * day;
const ticks = Array.from({ length: Math.floor((maximum - minimum) / step) + 1 }, (_, index) => minimum + index * step);
const dateLabel = (value) => new Date(value).toISOString().slice(0, 10);
const label = (index) => `${rows[index].label} (${rows[index].id})`;
const shortLabel = (index) => label(index).length > 22 ? label(index).slice(0, 21) + '…' : label(index);
return {
type: 'bar', data: { labels: rows.map((_, index) => label(index)), datasets: [{ label: 'Task Interval', data: rows.map((_, index) => [starts[index], ends[index]]), backgroundColor: '#3b82f6', categoryPercentage: 0.6, barPercentage: 1, maxBarThickness: 32 }] },
options: { indexAxis: 'y', responsive: true, maintainAspectRatio: false,
scales: {
x: { type: 'linear', min: minimum, max: maximum, afterBuildTicks: scale => { scale.ticks = ticks.map(value => ({ value })); }, ticks: { callback: value => dateLabel(Number(value)), maxRotation: 45 }, title: { display: true, text: 'Calendar Date (UTC)' } },
y: { grid: { display: false }, ticks: { autoSkip: true, maxTicksLimit: 12, callback: value => shortLabel(Number(value)) } },
},
plugins: { legend: { display: false }, title: { display: true, text: 'End Date Is Exclusive' }, tooltip: { callbacks: {
title: items => label(items[0].dataIndex),
label: item => { const i = item.dataIndex; return [`${headers[2]}: ${rows[i].start}`, `${headers[3]}: ${rows[i].end}`, `${headers[4]}: ${(ends[i] - starts[i]) / day}`]; },
} } },
},
};
}
const chart = new Chart(document.getElementById('myChart'), createConfig(chartData));Preview and code follow the same library selection.
Run This Example
Install the package below in a browser project such as Vite. Put the copied code in a client JavaScript module and add this container to the page before the module runs.
npm install chart.js@4.5.1<div style="height:320px"><canvas id="myChart"></canvas></div>The example includes its sample data. When removing the chart, destroy or dispose of its instance and disconnect any resize observer.
Reading This Example
This illustrative five-task schedule runs from 6 January to the exclusive end boundary on 23 January 2025. Requirements lasts three days, Design five, Build seven, Review five, and Release one. Requirements and Design overlap on 8 January. Build and Review overlap from 17 to 20 January, with 20 January excluded. The overall timeline spans 17 days; adding task durations would count overlapping days more than once.
All library tabs use these illustrative values. Rendering styles and library APIs differ, so use the table to compare exact numbers.
About this example & sample data
| Task ID | Task | Start | End (Exclusive) | Duration (Days) |
|---|---|---|---|---|
| T1 | Requirements | 2025-01-06 | 2025-01-09 | 3 |
| T2 | Design | 2025-01-08 | 2025-01-13 | 5 |
| T3 | Build | 2025-01-13 | 2025-01-20 | 7 |
| T4 | Review | 2025-01-17 | 2025-01-22 | 5 |
| T5 | Release | 2025-01-22 | 2025-01-23 | 1 |
READ THE CHART
Read Task Intervals on a Calendar
A Gantt Chart places each task on its own row and draws a bar from its start to its end. Horizontal position shows when work is scheduled; width shows elapsed duration. Compare rows vertically to see which intervals overlap.
Read the End Date as a Boundary
These examples include the start date and exclude the end date. A task from 6 to 9 January covers 6, 7, and 8 January, a duration of three days. A one-day task therefore ends the next day. A task ending on the same date another starts does not overlap that next task. The calculated duration uses this rule in every library.
Keep Calendar Spacing Intact
Dates use a shared elapsed-time scale: a seven-day task is seven times as wide as a one-day task. Weekends and holidays count, and gaps between tasks occupy real horizontal space. Inputs are whole UTC calendar dates with no times of day or daylight-saving adjustments. These durations measure calendar days, not working days or effort.
Keep Task Identity Separate From Names
Each row needs a unique task ID, while display names may repeat. The chart keeps the table order and shows the name beside its ID. Renaming a task does not combine it with another row. Short previews may shorten or omit crowded axis labels; the table and copied examples retain every task and its original dates.
Avoid Inferring Dependencies
Overlapping bars show shared time, not whether people or resources can handle the work. This editor contains dates and task labels only. It does not define dependencies, completion percentages, milestones, a business-day calendar, or a critical path. Use a Line Chart for measured values over time. The Seaborn example applies a theme to Matplotlib horizontal bars; Seaborn has no dedicated Gantt function here.