156LMS charts
The forms an LMS dashboard actually needs: engagement heatmap, score distribution, the enrollment funnel, and sparkline stat tiles. All from the same layer and the same slots.
Engagement heatmap
Activity by weekday and week — magnitude, so SEQUENTIAL fills, one hue. Empty cells stay grid-gray: zero is data. Hover or tab to a cell for its value.
markup
<figure class="ns-chart">
<div class="ns-chart__head"><span class="ns-chart__title">Learning activity</span><span class="ns-chart__sub">lessons completed · by weekday</span></div>
<div class="ns-chart__heat" style="--cols:12">
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">MON</span>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">MON W1 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">MON W2 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">MON W3 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">MON W4 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">MON W5 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">MON W6 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">MON W7 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">MON W8 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">MON W9 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">MON W10 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">MON W11 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">MON W12 · 48 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">TUE</span>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">TUE W1 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">TUE W2 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">TUE W3 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">TUE W4 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">TUE W5 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">TUE W6 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">TUE W7 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">TUE W8 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">TUE W9 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">TUE W10 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">TUE W11 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">TUE W12 · 36 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">WED</span>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">WED W1 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">WED W2 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">WED W3 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">WED W4 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">WED W5 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">WED W6 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">WED W7 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">WED W8 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">WED W9 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">WED W10 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">WED W11 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">WED W12 · 48 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">THU</span>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">THU W1 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">THU W2 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">THU W3 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">THU W4 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">THU W5 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">THU W6 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">THU W7 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">THU W8 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">THU W9 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">THU W10 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">THU W11 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">THU W12 · 36 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">FRI</span>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">FRI W1 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W2 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W3 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">FRI W4 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W5 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">FRI W6 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">FRI W7 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W8 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="3" tabindex="0"><span class="ns-chart__tip">FRI W9 · 36 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W10 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="4" tabindex="0"><span class="ns-chart__tip">FRI W11 · 48 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">FRI W12 · 24 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">SAT</span>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SAT W1 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SAT W2 · 12 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SAT W3 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">SAT W4 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SAT W5 · 12 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SAT W6 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">SAT W7 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SAT W8 · 12 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SAT W9 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SAT W10 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">SAT W11 · 24 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SAT W12 · 12 lessons</span></div>
</div>
<div class="ns-chart__heat-row" style="--cols:12">
<span class="ns-chart__heat-label">SUN</span>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W1 · 0 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W2 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SUN W3 · 12 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W4 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SUN W5 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">SUN W6 · 24 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W7 · 0 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W8 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SUN W9 · 12 lessons</span></div>
<div class="ns-chart__cell" tabindex="0"><span class="ns-chart__tip">SUN W10 · 0 lessons</span></div>
<div class="ns-chart__cell" data-seq="1" tabindex="0"><span class="ns-chart__tip">SUN W11 · 12 lessons</span></div>
<div class="ns-chart__cell" data-seq="2" tabindex="0"><span class="ns-chart__tip">SUN W12 · 24 lessons</span></div>
</div>
</div>
</figure>Score distribution
Quiz scores in ten-point bins — a histogram is a column chart whose x-axis is a scale. One series, slot 1, values in tooltips.
markup
<figure class="ns-chart">
<div class="ns-chart__head"><span class="ns-chart__title">Quiz score distribution</span><span class="ns-chart__sub">final assessment · n=412</span></div>
<div class="ns-chart__plot">
<div class="ns-chart__col" tabindex="0" style="--v:4%">
<span class="ns-chart__tip">0–10 · 8</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:6%">
<span class="ns-chart__tip">11–20 · 12</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:10%">
<span class="ns-chart__tip">21–30 · 21</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:16%">
<span class="ns-chart__tip">31–40 · 33</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:26%">
<span class="ns-chart__tip">41–50 · 54</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:42%">
<span class="ns-chart__tip">51–60 · 87</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:58%">
<span class="ns-chart__tip">61–70 · 120</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:72%">
<span class="ns-chart__tip">71–80 · 148</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:52%">
<span class="ns-chart__tip">81–90 · 107</span>
<div class="ns-chart__bar"></div>
</div>
<div class="ns-chart__col" tabindex="0" style="--v:28%">
<span class="ns-chart__tip">91–100 · 58</span>
<div class="ns-chart__bar"></div>
</div>
</div>
<div class="ns-chart__x"><span>0</span><span></span><span></span><span></span><span></span><span>50</span><span></span><span></span><span></span><span>100</span></div>
</figure>Enrollment funnel
Enrolled → started → completed → certified. Centered stages, sequential fills, and the drop-off named beside each stage — the loss IS the story.
markup
<figure class="ns-chart">
<div class="ns-chart__head"><span class="ns-chart__title">Course funnel</span><span class="ns-chart__sub">Apex basics · this quarter</span></div>
<div class="ns-chart__funnel">
<div class="ns-chart__fstage" tabindex="0">
<span class="ns-chart__tip">Enrolled · 460</span>
<span class="ns-chart__row-label">Enrolled</span>
<div class="ns-chart__ftrack"><div class="ns-chart__fbar" data-seq="1" style="--v:100%"></div></div>
<span class="ns-chart__row-value">460</span>
</div>
<div class="ns-chart__fstage" tabindex="0">
<span class="ns-chart__tip">Started · 350 · −24% vs previous</span>
<span class="ns-chart__row-label">Started</span>
<div class="ns-chart__ftrack"><div class="ns-chart__fbar" data-seq="2" style="--v:76%"></div></div>
<span class="ns-chart__row-value">350</span>
</div>
<div class="ns-chart__fstage" tabindex="0">
<span class="ns-chart__tip">Completed · 239 · −32% vs previous</span>
<span class="ns-chart__row-label">Completed</span>
<div class="ns-chart__ftrack"><div class="ns-chart__fbar" data-seq="3" style="--v:52%"></div></div>
<span class="ns-chart__row-value">239</span>
</div>
<div class="ns-chart__fstage" tabindex="0">
<span class="ns-chart__tip">Certified · 143 · −40% vs previous</span>
<span class="ns-chart__row-label">Certified</span>
<div class="ns-chart__ftrack"><div class="ns-chart__fbar" data-seq="4" style="--v:31%"></div></div>
<span class="ns-chart__row-value">143</span>
</div>
</div>
</figure>Stat tiles with sparklines
The dashboard's first row: label, value, delta in status ink, and a 12-point sparkline — no axes, no grid; the tile's job is the number.
- 1,284 ▲ 12%
- Active learners
- 82 ▲ 9%
- Completions / wk
- 71 ▼ 2%
- Avg quiz score
markup
<dl class="ns-statband" style="background:var(--color-surface)">
<div class="ns-statband__cell">
<dd class="ns-statband__value">1,284 <span class="ns-chart__delta" data-dir="up">▲ 12%</span></dd>
<dt class="ns-statband__label">Active learners</dt>
<svg class="ns-chart__spark" viewBox="0 0 320 30" preserveAspectRatio="none" aria-hidden="true">
<polyline class="ns-chart__line" data-c="1" vector-effect="non-scaling-stroke" points="0,26 29,22 58,24 87,18 116,20 145,14 174,16 203,10 232,12 261,8 290,9 320,4"/>
</svg>
</div>
<div class="ns-statband__cell">
<dd class="ns-statband__value">82 <span class="ns-chart__delta" data-dir="up">▲ 9%</span></dd>
<dt class="ns-statband__label">Completions / wk</dt>
<svg class="ns-chart__spark" viewBox="0 0 320 30" preserveAspectRatio="none" aria-hidden="true">
<polyline class="ns-chart__line" data-c="1" vector-effect="non-scaling-stroke" points="0,22 29,24 58,20 87,22 116,16 145,18 174,14 203,16 232,10 261,14 290,8 320,6"/>
</svg>
</div>
<div class="ns-statband__cell">
<dd class="ns-statband__value">71 <span class="ns-chart__delta" data-dir="down">▼ 2%</span></dd>
<dt class="ns-statband__label">Avg quiz score</dt>
<svg class="ns-chart__spark" viewBox="0 0 320 30" preserveAspectRatio="none" aria-hidden="true">
<polyline class="ns-chart__line" data-c="1" vector-effect="non-scaling-stroke" points="0,10 29,12 58,8 87,14 116,12 145,16 174,14 203,18 232,16 261,20 290,18 320,22"/>
</svg>
</div>
</dl>