Basic Gantt Chart — MUI X Charts

A Gantt chart is a horizontal bar chart that visualizes project schedules and timelines. Each task is represented as a horizontal bar spanning from its start date to end date, making it easy to see task durations, overlaps, and the overall project timeline at a glance. Gantt charts are essential for project management, helping teams understand task sequences and identify scheduling conflicts.

Basic Gantt Chart rendered with MUI X Charts

Renders

JavaScript source (MUI X Charts)

// anyplot.ai
// gantt-basic: Basic Gantt Chart
// Library: muix 7.29.1 | JavaScript 22.23.2
// Quality: 88/100 | Created: 2026-09-05
import { BarChart } from "@mui/x-charts/BarChart";
import { ChartsReferenceLine } from "@mui/x-charts/ChartsReferenceLine";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) ----------------------------------------
// Website redesign project: 11 tasks across 4 phases, day-offsets from the
// project kickoff (Jan 5, 2026 = day 0) so the x-axis is a plain linear scale
// that a valueFormatter renders back as calendar dates.
const DAY_MS = 86400000;
const toDay = (year, month, date) => Date.UTC(year, month, date) / DAY_MS;
const PROJECT_START = toDay(2026, 0, 5);

const CATEGORIES = ["Design", "Development", "Testing", "Launch"];
const CATEGORY_COLOR = Object.fromEntries(CATEGORIES.map((category, i) => [category, t.palette[i]]));

const TASKS = [
  { task: "Requirements Gathering", category: "Design", start: [2026, 0, 5], end: [2026, 0, 12] },
  { task: "Wireframing", category: "Design", start: [2026, 0, 10], end: [2026, 0, 20] },
  { task: "Visual Design", category: "Design", start: [2026, 0, 18], end: [2026, 0, 30] },
  { task: "Backend Development", category: "Development", start: [2026, 0, 26], end: [2026, 1, 20] },
  { task: "Frontend Development", category: "Development", start: [2026, 0, 29], end: [2026, 1, 24] },
  { task: "API Integration", category: "Development", start: [2026, 1, 16], end: [2026, 1, 27] },
  { task: "Unit Testing", category: "Testing", start: [2026, 1, 21], end: [2026, 2, 1] },
  { task: "QA & Bug Fixes", category: "Testing", start: [2026, 1, 27], end: [2026, 2, 10] },
  { task: "User Acceptance Testing", category: "Testing", start: [2026, 2, 6], end: [2026, 2, 14] },
  { task: "Deployment", category: "Launch", start: [2026, 2, 12], end: [2026, 2, 16] },
  { task: "Post-Launch Monitoring", category: "Launch", start: [2026, 2, 14], end: [2026, 2, 25] },
].map((row) => ({
  task: row.task,
  category: row.category,
  start: toDay(...row.start) - PROJECT_START,
  end: toDay(...row.end) - PROJECT_START,
}));

const TASK_NAMES = TASKS.map((row) => row.task);
const MAX_DAY = Math.max(...TASKS.map((row) => row.end));
const STATUS_DAY = toDay(2026, 1, 20) - PROJECT_START;

const dateFormatter = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" });
const formatDay = (offsetDays) => dateFormatter.format(new Date((PROJECT_START + offsetDays) * DAY_MS));

const TICKS = [];
for (let d = 0; d <= MAX_DAY; d += 14) TICKS.push(d);

// --- Series: an invisible "offset" segment (start of timeline -> task start)
// stacked with, per category, a solid "duration" segment — null everywhere
// except the row that belongs to it — so each task lands as a floating bar
// at its correct start/end day offsets. --------------------------------------
const OFFSET_SERIES = {
  id: "offset",
  stack: "timeline",
  color: "transparent",
  data: TASKS.map((row) => row.start),
  valueFormatter: () => null,
};

const CATEGORY_SERIES = CATEGORIES.map((category) => ({
  id: category,
  label: category,
  stack: "timeline",
  color: CATEGORY_COLOR[category],
  data: TASKS.map((row) => (row.category === category ? row.end - row.start : null)),
  valueFormatter: (value, { dataIndex }) =>
    value == null ? null : `${formatDay(TASKS[dataIndex].start)} – ${formatDay(TASKS[dataIndex].end)}`,
}));

// --- Chart (default-exported component — the harness mounts it) ------------
export default function Chart() {
  const W = window.ANYPLOT_SIZE.width;
  const H = window.ANYPLOT_SIZE.height;
  const TITLE_TOP = 28;
  const LEGEND_TOP = 76;
  const CHART_TOP = 104;

  const title = "Website Redesign Timeline · gantt-basic · javascript · muix · anyplot.ai";
  const titleSize = title.length > 67 ? Math.round((26 * 67) / title.length) : 26;

  return (
    <Box sx={{ position: "relative", width: W, height: H, bgcolor: t.pageBg }}>
      <Box sx={{ position: "absolute", top: TITLE_TOP, left: 56, right: 56 }}>
        <Typography sx={{ color: t.ink, fontSize: titleSize, fontWeight: 500 }}>{title}</Typography>
      </Box>

      <Stack direction="row" spacing={3} sx={{ position: "absolute", top: LEGEND_TOP, left: 56, right: 56 }}>
        {CATEGORIES.map((category) => (
          <Stack key={category} direction="row" spacing={1} alignItems="center">
            <Box sx={{ width: 14, height: 14, borderRadius: "3px", bgcolor: CATEGORY_COLOR[category] }} />
            <Typography sx={{ color: t.inkSoft, fontSize: 14 }}>{category}</Typography>
          </Stack>
        ))}
      </Stack>

      <Box sx={{ position: "absolute", top: CHART_TOP, left: 0, right: 0, bottom: 0 }}>
        <BarChart
          width={W}
          height={H - CHART_TOP}
          layout="horizontal"
          skipAnimation
          borderRadius={3}
          series={[OFFSET_SERIES, ...CATEGORY_SERIES]}
          grid={{ vertical: true }}
          xAxis={[
            {
              min: 0,
              max: MAX_DAY + 4,
              tickInterval: TICKS,
              valueFormatter: (value) => formatDay(value),
              label: "Project Timeline",
              labelStyle: { fontSize: 15, fill: t.ink },
              tickLabelStyle: { fontSize: 13, fill: t.inkSoft },
              disableTicks: true,
            },
          ]}
          yAxis={[
            {
              scaleType: "band",
              data: TASK_NAMES,
              tickLabelStyle: { fontSize: 14, fill: t.inkSoft },
              disableTicks: true,
              categoryGapRatio: 0.35,
            },
          ]}
          margin={{ top: 16, right: 60, bottom: 56, left: 232 }}
          slotProps={{ legend: { hidden: true } }}
          sx={{
            "& .MuiChartsAxis-line": { stroke: t.inkSoft },
            "& .MuiChartsGrid-line": { stroke: t.grid },
          }}
        >
          <ChartsReferenceLine
            x={STATUS_DAY}
            label={`Status: ${formatDay(STATUS_DAY)}`}
            labelAlign="end"
            lineStyle={{ stroke: t.ink, strokeDasharray: "6 4", strokeWidth: 2 }}
            labelStyle={{ fontSize: 13, fill: t.ink, fontWeight: 600 }}
          />
        </BarChart>
      </Box>
    </Box>
  );
}

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/gantt-basic/muix/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "gantt-basic",
  "language": "javascript",
  "library": "muix",
  "page": "https://anyplot.ai/gantt-basic/javascript/muix",
  "hub": "https://anyplot.ai/gantt-basic",
  "code_json": "https://api.anyplot.ai/specs/gantt-basic/muix/code",
  "spec_json": "https://api.anyplot.ai/specs/gantt-basic",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/gantt-basic/javascript/muix/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/gantt-basic/javascript/muix/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/gantt-basic/javascript/muix/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/gantt-basic/javascript/muix/plot-dark.html",
  "quality_score": 88.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Basic Gantt Chart on anyplot.ai.

Other implementations