v1.2.0
  1. ds
  2. Data display
  3. Calendar heatmap

Calendar heatmap

A year of days, one square each.

A year at a glance, one square per day, Sunday at the top of each week. It is the commit calendar from fin1te.com, generalised: deploys, pipeline runs, incidents, anything counted per day. It reuses the heatmap cells and heat scale.

5,002 runs in the last year
Show code
<div class="cal-scroll">
  <div class="cal-hm" style="--weeks:53" role="img" aria-label="5,002 pipeline runs in the last year">
    <div class="ch-months"><span style="--w:1">Oct</span><span style="--w:5">Nov</span> …</div>
    <div class="ch-days"><span></span><span>Mon</span><span></span><span>Wed</span><span></span><span>Fri</span><span></span></div>
    <div class="ch-cells">
      <i class="hm-cell" data-l="2" data-at="Sun 5 Oct 2025"></i> … one per day, a column per week
    </div>
  </div>
</div>
<div class="cal-foot">
  <span>5,002 runs in the last year</span>
  <div class="hm-legend">…</div>
</div>

The cells are a grid with seven rows that fills column by column, so the markup is just the days in order. Month labels sit on the week where the month starts, via --w. Below 40rem the calendar scrolls sideways inside .cal-scroll rather than shrinking cells past legibility. Hover a day for its count.

ClassOnWhat it does
.cal-hmdivDay labels, month labels and cells. Set --weeks (53).
.ch-months > spanspanA month label starting at week --w.
.ch-daysdivSeven row labels; leave some empty.
.ch-cells > .hm-celliOne per day in order, data-l 0 to 5. .pad hides a cell before the first day.
.cal-scrolldivScrolls the calendar on narrow screens, keeping cells at least 0.6rem.
.cal-footdivThe total on the left, the legend on the right.

Accessibility

  • The calendar is one image with the summary as its label. Offer counts per week or month as a table.
  • Do not make 365 cells tab stops. If days are clickable, use one tab stop and arrow keys.