Agile Sprint Burndown Chart — MUI X Charts

A sprint burndown chart tracks the amount of remaining work in an agile sprint over time, plotted as a step (or line) series that descends as tasks are completed. A straight ideal-burndown guideline runs diagonally from the total committed scope on day one down to zero on the final day, giving the team an at-a-glance reference for whether they are ahead of or behind schedule. It is one of the most widely used project-management visualizations in software development, surfacing scope creep, stalled progress, and end-of-sprint risk early enough to act on.

Agile Sprint Burndown Chart rendered with MUI X Charts

JavaScript source (MUI X Charts)

// anyplot.ai
// burndown-sprint: Agile Sprint Burndown Chart
// Library: muix 7.29.1 | JavaScript 22.22.3
// Quality: 91/100 | Created: 2026-06-14

import { LineChart } from "@mui/x-charts/LineChart";
import { ChartsReferenceLine } from "@mui/x-charts";
import { useXScale, useDrawingArea } from "@mui/x-charts/hooks";

const t = window.ANYPLOT_TOKENS;

// Sprint: start state + 10 working days (2 weeks Mon–Fri)
// Scope change: +8 story points added by stakeholder on Thu of Week 1 (Day 4)
const days = [
  "Start",
  "Mon 1", "Tue 2", "Wed 3", "Thu 4", "Fri 5",
  "Mon 8", "Tue 9", "Wed 10", "Thu 11", "Fri 12",
];

// Remaining story points recorded at end of each day.
// Thu 4: team completed 2 pts but +8 scope added → jump from 32 to 38
const actual = [40, 37, 34, 32, 38, 34, 28, 21, 14, 7, 2];

// Ideal burndown: straight line from 40 → 0 across 10 working days (4 pts/day)
const ideal = [40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0];

const TITLE_H = 60;

// SVG overlay: shades the Fri→Mon gap to represent the weekend break
function WeekendBand() {
  const xScale = useXScale();
  const { top, height } = useDrawingArea();

  if (typeof xScale.bandwidth !== "function") return null;

  const bw = xScale.bandwidth();
  const x1 = xScale("Fri 5");
  const x2 = xScale("Mon 8");

  if (x1 == null || x2 == null) return null;

  // Shade from the mid-point of Fri 5 to mid-point of Mon 8 (one bandwidth wide)
  // — visually straddles the weekend discontinuity between the two adjacent bands
  const rectX = x1 + bw * 0.5;
  const rectW = x2 + bw * 0.5 - rectX;

  return (
    <rect
      x={rectX}
      y={top}
      width={rectW}
      height={height}
      fill={t.inkSoft}
      fillOpacity={0.12}
    />
  );
}

export default function Chart() {
  const { width, height } = window.ANYPLOT_SIZE;

  return (
    <div
      style={{
        width,
        height,
        background: t.pageBg,
        overflow: "hidden",
        boxSizing: "border-box",
        fontFamily: "'Roboto', 'Helvetica Neue', Arial, sans-serif",
      }}
    >
      <div
        style={{
          height: TITLE_H,
          display: "flex",
          alignItems: "center",
          paddingLeft: 28,
          paddingRight: 28,
        }}
      >
        <span
          style={{
            color: t.ink,
            fontSize: 22,
            fontWeight: 500,
            letterSpacing: 0.3,
          }}
        >
          burndown-sprint · javascript · muix · anyplot.ai
        </span>
      </div>

      <LineChart
        width={width}
        height={height - TITLE_H}
        skipAnimation
        xAxis={[{
          scaleType: "band",
          data: days,
          tickLabelStyle: { fontSize: 13, fill: t.inkSoft },
        }]}
        yAxis={[{
          label: "Story Points Remaining",
          min: 0,
          max: 48,
          tickLabelStyle: { fontSize: 13, fill: t.inkSoft },
          labelStyle: { fontSize: 15, fill: t.ink },
        }]}
        series={[
          {
            id: "actual",
            data: actual,
            label: "Actual Remaining",
            curve: "step",
            showMark: true,
            color: t.palette[0],
          },
          {
            id: "ideal",
            data: ideal,
            label: "Ideal Burndown",
            curve: "linear",
            showMark: false,
            color: t.inkSoft,
            area: true,
          },
        ]}
        sx={{
          "& .MuiLineElement-series-ideal": {
            strokeDasharray: "10 6",
            strokeOpacity: 0.6,
          },
          "& .MuiAreaElement-series-ideal": {
            fill: t.palette[0],
            fillOpacity: 0.07,
          },
          "& .MuiLineElement-series-actual": {
            strokeWidth: 3,
          },
          "& .MuiMarkElement-series-actual": {
            strokeWidth: 2,
          },
        }}
        slotProps={{
          legend: {
            itemMarkWidth: 20,
            itemMarkHeight: 3,
            markGap: 8,
            itemGap: 24,
            labelStyle: { fontSize: 14, fill: t.ink },
          },
        }}
      >
        {/* Weekend shading: straddled rect at Fri→Mon discontinuity */}
        <WeekendBand />

        <ChartsReferenceLine
          x="Thu 4"
          label="Scope +8 pts"
          labelAlign="start"
          lineStyle={{
            stroke: t.palette[3],
            strokeWidth: 2,
            strokeDasharray: "5 4",
          }}
          labelStyle={{
            fill: t.palette[3],
            fontSize: 13,
            fontWeight: 500,
          }}
        />
      </LineChart>
    </div>
  );
}

Part of Agile Sprint Burndown Chart on anyplot.ai.

Other implementations