Velocity

Rate at which work is completed.

Platform velocity improving
18S1 24S2 30S3 36S4 42S5 28S1 31S2 29S3 32S4 30S5 34S1 29S2 24S3 19S4 14S5

Trending up: last sprint closed at 42 points, up from 18 five sprints ago. Holding steady around 30 points per sprint for the last five sprints. Trending down: last sprint closed at 14 points, down from 34 five sprints ago.

html

<div class="velocity" data-trend="improving">
  <div class="velocity__header">
    <span class="velocity__title">Platform velocity</span>
    <span class="velocity__trend-label" data-trend="improving">improving</span>
  </div>
  <svg class="velocity__chart" viewBox="0 0 260 130" width="260" height="130" role="img" aria-label="Velocity across the last five sprints, trend improving">
    <line x1="4" y1="110" x2="256" y2="110" stroke="#241430" stroke-width="1"></line>
    <g class="velocity__series velocity__series--improving">
      <rect x="10" y="74" width="28" height="36" fill="#BFD9F2"></rect><text class="velocity__value-text" x="24" y="68" font-size="9" text-anchor="middle">18</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="62" width="28" height="48" fill="#BFD9F2"></rect><text class="velocity__value-text" x="72" y="56" font-size="9" text-anchor="middle">24</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="50" width="28" height="60" fill="#BFD9F2"></rect><text class="velocity__value-text" x="120" y="44" font-size="9" text-anchor="middle">30</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="38" width="28" height="72" fill="#A8E6C1"></rect><text class="velocity__value-text" x="168" y="32" font-size="9" text-anchor="middle">36</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="26" width="28" height="84" fill="#A8E6C1"></rect><text class="velocity__value-text" x="216" y="20" font-size="9" text-anchor="middle">42</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
    <g class="velocity__series velocity__series--steady">
      <rect x="10" y="54" width="28" height="56" fill="#BFD9F2"></rect><text class="velocity__value-text" x="24" y="48" font-size="9" text-anchor="middle">28</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="48" width="28" height="62" fill="#BFD9F2"></rect><text class="velocity__value-text" x="72" y="42" font-size="9" text-anchor="middle">31</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="52" width="28" height="58" fill="#BFD9F2"></rect><text class="velocity__value-text" x="120" y="46" font-size="9" text-anchor="middle">29</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="46" width="28" height="64" fill="#BFD9F2"></rect><text class="velocity__value-text" x="168" y="40" font-size="9" text-anchor="middle">32</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="50" width="28" height="60" fill="#BFD9F2"></rect><text class="velocity__value-text" x="216" y="44" font-size="9" text-anchor="middle">30</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
    <g class="velocity__series velocity__series--declining">
      <rect x="10" y="42" width="28" height="68" fill="#D9C8F0"></rect><text class="velocity__value-text" x="24" y="36" font-size="9" text-anchor="middle">34</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="52" width="28" height="58" fill="#D9C8F0"></rect><text class="velocity__value-text" x="72" y="46" font-size="9" text-anchor="middle">29</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="62" width="28" height="48" fill="#D9C8F0"></rect><text class="velocity__value-text" x="120" y="56" font-size="9" text-anchor="middle">24</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="72" width="28" height="38" fill="#F5C2E0"></rect><text class="velocity__value-text" x="168" y="66" font-size="9" text-anchor="middle">19</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="82" width="28" height="28" fill="#F5C2E0"></rect><text class="velocity__value-text" x="216" y="76" font-size="9" text-anchor="middle">14</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
  </svg>
  <p class="velocity__summary">
    <span class="velocity__summary-text velocity__summary-text--improving">Trending up: last sprint closed at 42 points, up from 18 five sprints ago.</span>
    <span class="velocity__summary-text velocity__summary-text--steady">Holding steady around 30 points per sprint for the last five sprints.</span>
    <span class="velocity__summary-text velocity__summary-text--declining">Trending down: last sprint closed at 14 points, down from 34 five sprints ago.</span>
  </p>
</div>
<style>
.velocity { font-family: system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 16px; border-radius: 10px; max-width: 300px; box-sizing: border-box; }
.velocity__header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; }
.velocity__title { font-weight: 700; font-size: 14px; }
.velocity__trend-label { font-size: 11px; font-weight: 700; text-transform: capitalize; padding: 2px 8px; border-radius: 999px; }
.velocity__trend-label[data-trend="improving"] { background: #A8E6C150; color: #1c5c34; }
.velocity__trend-label[data-trend="steady"] { background: #BFD9F250; color: #1a3a5c; }
.velocity__trend-label[data-trend="declining"] { background: #F5C2E050; color: #8a1050; }
.velocity__chart { display: block; }
.velocity__series { display: none; }
.velocity[data-trend="improving"] .velocity__series--improving { display: inline; }
.velocity[data-trend="steady"] .velocity__series--steady { display: inline; }
.velocity[data-trend="declining"] .velocity__series--declining { display: inline; }
.velocity--hide-values .velocity__value-text { display: none; }
.velocity__summary { margin: 8px 0 0; font-size: 12px; }
.velocity__summary-text { display: none; }
.velocity[data-trend="improving"] .velocity__summary-text--improving { display: inline; }
.velocity[data-trend="steady"] .velocity__summary-text--steady { display: inline; }
.velocity[data-trend="declining"] .velocity__summary-text--declining { display: inline; }
</style>

tailwind

<div class="velocity-tw font-sans text-[#241430] bg-[#FAF7F2] p-4 rounded-[10px] max-w-[300px] box-border" data-trend="improving">
  <div class="flex items-baseline justify-between mb-1.5">
    <span class="font-bold text-sm">Platform velocity</span>
    <span class="velocity-tw__trend-label text-[11px] font-bold capitalize px-2 py-0.5 rounded-full" data-trend="improving">improving</span>
  </div>
  <svg class="block" viewBox="0 0 260 130" width="260" height="130" role="img" aria-label="Velocity across the last five sprints, trend improving">
    <line x1="4" y1="110" x2="256" y2="110" stroke="#241430" stroke-width="1"></line>
    <g class="velocity-tw__series velocity-tw__series--improving">
      <rect x="10" y="74" width="28" height="36" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="24" y="68" font-size="9" text-anchor="middle">18</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="62" width="28" height="48" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="72" y="56" font-size="9" text-anchor="middle">24</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="50" width="28" height="60" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="120" y="44" font-size="9" text-anchor="middle">30</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="38" width="28" height="72" fill="#A8E6C1"></rect><text class="velocity-tw__value-text" x="168" y="32" font-size="9" text-anchor="middle">36</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="26" width="28" height="84" fill="#A8E6C1"></rect><text class="velocity-tw__value-text" x="216" y="20" font-size="9" text-anchor="middle">42</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
    <g class="velocity-tw__series velocity-tw__series--steady">
      <rect x="10" y="54" width="28" height="56" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="24" y="48" font-size="9" text-anchor="middle">28</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="48" width="28" height="62" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="72" y="42" font-size="9" text-anchor="middle">31</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="52" width="28" height="58" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="120" y="46" font-size="9" text-anchor="middle">29</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="46" width="28" height="64" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="168" y="40" font-size="9" text-anchor="middle">32</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="50" width="28" height="60" fill="#BFD9F2"></rect><text class="velocity-tw__value-text" x="216" y="44" font-size="9" text-anchor="middle">30</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
    <g class="velocity-tw__series velocity-tw__series--declining">
      <rect x="10" y="42" width="28" height="68" fill="#D9C8F0"></rect><text class="velocity-tw__value-text" x="24" y="36" font-size="9" text-anchor="middle">34</text><text x="24" y="122" font-size="9" text-anchor="middle">S1</text>
      <rect x="58" y="52" width="28" height="58" fill="#D9C8F0"></rect><text class="velocity-tw__value-text" x="72" y="46" font-size="9" text-anchor="middle">29</text><text x="72" y="122" font-size="9" text-anchor="middle">S2</text>
      <rect x="106" y="62" width="28" height="48" fill="#D9C8F0"></rect><text class="velocity-tw__value-text" x="120" y="56" font-size="9" text-anchor="middle">24</text><text x="120" y="122" font-size="9" text-anchor="middle">S3</text>
      <rect x="154" y="72" width="28" height="38" fill="#F5C2E0"></rect><text class="velocity-tw__value-text" x="168" y="66" font-size="9" text-anchor="middle">19</text><text x="168" y="122" font-size="9" text-anchor="middle">S4</text>
      <rect x="202" y="82" width="28" height="28" fill="#F5C2E0"></rect><text class="velocity-tw__value-text" x="216" y="76" font-size="9" text-anchor="middle">14</text><text x="216" y="122" font-size="9" text-anchor="middle">S5</text>
    </g>
  </svg>
  <p class="mt-2 text-xs">
    <span class="velocity-tw__summary-text velocity-tw__summary-text--improving">Trending up: last sprint closed at 42 points, up from 18 five sprints ago.</span>
    <span class="velocity-tw__summary-text velocity-tw__summary-text--steady">Holding steady around 30 points per sprint for the last five sprints.</span>
    <span class="velocity-tw__summary-text velocity-tw__summary-text--declining">Trending down: last sprint closed at 14 points, down from 34 five sprints ago.</span>
  </p>
</div>
<style>
.velocity-tw__trend-label[data-trend="improving"] { background: #A8E6C150; color: #1c5c34; }
.velocity-tw__trend-label[data-trend="steady"] { background: #BFD9F250; color: #1a3a5c; }
.velocity-tw__trend-label[data-trend="declining"] { background: #F5C2E050; color: #8a1050; }
.velocity-tw__series { display: none; }
.velocity-tw[data-trend="improving"] .velocity-tw__series--improving { display: inline; }
.velocity-tw[data-trend="steady"] .velocity-tw__series--steady { display: inline; }
.velocity-tw[data-trend="declining"] .velocity-tw__series--declining { display: inline; }
.velocity-tw--hide-values .velocity-tw__value-text { display: none; }
.velocity-tw__summary-text { display: none; }
.velocity-tw[data-trend="improving"] .velocity-tw__summary-text--improving { display: inline; }
.velocity-tw[data-trend="steady"] .velocity-tw__summary-text--steady { display: inline; }
.velocity-tw[data-trend="declining"] .velocity-tw__summary-text--declining { display: inline; }
</style>

react

export function Velocity({
  teamName = "Platform",
  trend = "improving",
  accent = "#241430",
  showValues = true,
}) {
  const series = {
    improving: { values: [18, 24, 30, 36, 42], colors: ["#BFD9F2", "#BFD9F2", "#BFD9F2", "#A8E6C1", "#A8E6C1"],
      summary: "Trending up: last sprint closed at 42 points, up from 18 five sprints ago." },
    steady: { values: [28, 31, 29, 32, 30], colors: ["#BFD9F2", "#BFD9F2", "#BFD9F2", "#BFD9F2", "#BFD9F2"],
      summary: "Holding steady around 30 points per sprint for the last five sprints." },
    declining: { values: [34, 29, 24, 19, 14], colors: ["#D9C8F0", "#D9C8F0", "#D9C8F0", "#F5C2E0", "#F5C2E0"],
      summary: "Trending down: last sprint closed at 14 points, down from 34 five sprints ago." },
  }[trend];
  const trendColor = {
    improving: { background: "#A8E6C150", color: "#1c5c34" },
    steady: { background: "#BFD9F250", color: "#1a3a5c" },
    declining: { background: "#F5C2E050", color: "#8a1050" },
  }[trend];
  const baseline = 110;
  const bars = series.values.map((v, i) => ({
    x: 10 + i * 48,
    height: v * 2,
    y: baseline - v * 2,
    value: v,
    color: series.colors[i],
    label: "S" + (i + 1),
  }));
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", color: "#241430", background: "#FAF7F2", padding: 16,
      borderRadius: 10, maxWidth: 300, boxSizing: "border-box" }}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 6 }}>
        <span style={{ fontWeight: 700, fontSize: 14 }}>{teamName} velocity</span>
        <span style={{ fontSize: 11, fontWeight: 700, textTransform: "capitalize", padding: "2px 8px", borderRadius: 999, ...trendColor }}>{trend}</span>
      </div>
      <svg viewBox="0 0 260 130" width="260" height="130" role="img" aria-label={"Velocity across the last five sprints, trend " + trend} style={{ display: "block" }}>
        <line x1="4" y1={baseline} x2="256" y2={baseline} stroke={accent} strokeWidth="1" />
        {bars.map((bar) => (
          <g key={bar.label}>
            <rect x={bar.x} y={bar.y} width="28" height={bar.height} fill={bar.color} />
            {showValues && <text x={bar.x + 14} y={bar.y - 6} fontSize="9" textAnchor="middle">{bar.value}</text>}
            <text x={bar.x + 14} y="122" fontSize="9" textAnchor="middle">{bar.label}</text>
          </g>
        ))}
      </svg>
      <p style={{ margin: "8px 0 0", fontSize: 12 }}>{series.summary}</p>
    </div>
  );
}