Skip to content
Folio

Data

CalendarHeatmap

A year of daily readings, as a week-by-week grid.

Usage

When to reach for it

The readings are dated and the question is about the calendar. Heatmap is the grid underneath and knows nothing about dates; this is the arrangement everybody writes on top of it and nobody writes the same way twice.

Ships from@misoto22/design/charts

TSX
import { CalendarHeatmap } from '@misoto22/design/charts'

Notes

A year of daily readings, as a week-by-week grid.

Heatmap draws a grid of named rows and columns and knows nothing about dates; this is the arrangement everybody writes on top of it and nobody writes the same way twice — a column per week, a row per weekday, a month name on the first column it touches, and the days either side of the window left as gaps rather than as zeroes.

The grid is built from the DATES rather than from the order of the array, so a gap in the data is a gap on the calendar. That is the failure this exists to prevent: given a bare list of counts, a missing Tuesday shifts every reading after it by one cell, and the result is a plausible picture of a year that did not happen.

Every date is arithmetic on UTC midnights. A local-time calendar drawn in two timezones is two different calendars, and the disagreement is exactly one day wide — small enough to survive review and large enough to move a reading into the wrong week.

Anatomy

CalendarHeatmap anatomy
ElementDescription
GridrequiredA Heatmap: one column per week, one row per weekday, drawn from the dates rather than from the order of the array. Every date is arithmetic on UTC midnights, so the same window renders identically in every timezone.
Windowrequiredfrom and to, or the earliest and latest date in values when they are left off. The grid runs back to the start of the first week and on to the end of the last, so a column is always a whole week.
Weekday rowsrequiredSeven row headers from weekdayLabels, always Sunday-first in the ARRAY and rotated onto the grid by weekStartsOn — so a Monday-first calendar and a translation are two separate decisions.
Month headersA name from monthLabels on the first column each month touches, blank on the rest. The blanks carry a run of zero-width spaces so the grid can still tell them apart, which is what a lookup by column NAME requires.
GapsA day inside the window with no entry, and every day in the leading and trailing partial weeks: a dashed outline with an announced “no data”, never the palest cell on the ramp.
Cell readingWhat describe returns for that day, announced with the cell. Keyed by the cell rather than by the number, so two days with the same count are two different readings.

Best practices

Do

  • Pass from and to whenever the window is a fact about the question rather than about the data. Derived from the values, a quiet January does not exist — the grid silently becomes a different window from the one beside it, and the two are then compared anyway.
  • Write describe so it names the unit. The row and column a cell is announced with are a weekday and a month over a block of five weeks, so without it the reading a screen reader gets is a date and a bare number.
  • Pin domain to compare two calendars. A quiet year and a busy one drawn on their own domains look identical, and the comparison the reader came for is not merely lost but inverted.

Don’t

  • Do not send a zero for a day nothing was recorded. Null is drawn as a gap and zero as the palest cell, and a page that draws them alike invites the reader to explain an outage that was a hole in collection.
  • Do not hand it dates carrying a time or a zone. Every bound is parsed as a UTC midnight from YYYY-MM-DD, so a timestamp that is 23:00 somewhere lands on the day before it in the grid.
  • Do not reach for it where the rows are not weekdays. An hour-by-weekday load or a confusion matrix is a Heatmap, and going through this one means inventing dates for cells that do not have any.

Examples

default

Half a year, built from the dates rather than from the order of the array — which is the whole difference from a bare list of counts, where one missing day shifts every reading after it by a cell and draws a plausible picture of a year that did not happen. The fortnight in March is null rather than zero, so it renders as a dashed gap and announces no data: nothing happened and nothing was recorded are different readings, and a page that draws them alike invites the reader to explain an outage that was a hole in collection. describe names the unit, because the row and column a cell is announced with are a weekday and a month over a block of five weeks.

Commits per dayDarker is busier
Commits per day
RowJan​​​​​Feb​​​​​​​​​​​​​​​​​​​​​​Mar​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​Apr​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​May​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​Jun​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
Sun2 commits on 2026-01-04Sun, Jan3 commits on 2026-01-11Sun, ​4 commits on 2026-01-18Sun, ​​3 commits on 2026-01-25Sun, ​​​2 commits on 2026-02-01Sun, Feb​​​​1 commits on 2026-02-08Sun, ​​​​​0 commits on 2026-02-15Sun, ​​​​​​1 commits on 2026-02-22Sun, ​​​​​​​2 commits on 2026-03-01Sun, Mar​​​​​​​​3 commits on 2026-03-08Sun, ​​​​​​​​​Sun, ​​​​​​​​​​: no dataSun, ​​​​​​​​​​​: no data2 commits on 2026-03-29Sun, ​​​​​​​​​​​​1 commits on 2026-04-05Sun, Apr​​​​​​​​​​​​​0 commits on 2026-04-12Sun, ​​​​​​​​​​​​​​0 commits on 2026-04-19Sun, ​​​​​​​​​​​​​​​2 commits on 2026-04-26Sun, ​​​​​​​​​​​​​​​​3 commits on 2026-05-03Sun, May​​​​​​​​​​​​​​​​​4 commits on 2026-05-10Sun, ​​​​​​​​​​​​​​​​​​4 commits on 2026-05-17Sun, ​​​​​​​​​​​​​​​​​​​2 commits on 2026-05-24Sun, ​​​​​​​​​​​​​​​​​​​​1 commits on 2026-05-31Sun, ​​​​​​​​​​​​​​​​​​​​​0 commits on 2026-06-07Sun, Jun​​​​​​​​​​​​​​​​​​​​​​0 commits on 2026-06-14Sun, ​​​​​​​​​​​​​​​​​​​​​​​2 commits on 2026-06-21Sun, ​​​​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-28Sun, ​​​​​​​​​​​​​​​​​​​​​​​​​
Mon10 commits on 2026-01-05Mon, Jan14 commits on 2026-01-12Mon, ​15 commits on 2026-01-19Mon, ​​13 commits on 2026-01-26Mon, ​​​9 commits on 2026-02-02Mon, Feb​​​​4 commits on 2026-02-09Mon, ​​​​​3 commits on 2026-02-16Mon, ​​​​​​5 commits on 2026-02-23Mon, ​​​​​​​9 commits on 2026-03-02Mon, Mar​​​​​​​​13 commits on 2026-03-09Mon, ​​​​​​​​​Mon, ​​​​​​​​​​: no dataMon, ​​​​​​​​​​​: no data9 commits on 2026-03-30Mon, ​​​​​​​​​​​​5 commits on 2026-04-06Mon, Apr​​​​​​​​​​​​​3 commits on 2026-04-13Mon, ​​​​​​​​​​​​​​5 commits on 2026-04-20Mon, ​​​​​​​​​​​​​​​9 commits on 2026-04-27Mon, ​​​​​​​​​​​​​​​​13 commits on 2026-05-04Mon, May​​​​​​​​​​​​​​​​​15 commits on 2026-05-11Mon, ​​​​​​​​​​​​​​​​​​13 commits on 2026-05-18Mon, ​​​​​​​​​​​​​​​​​​​9 commits on 2026-05-25Mon, ​​​​​​​​​​​​​​​​​​​​5 commits on 2026-06-01Mon, ​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-08Mon, Jun​​​​​​​​​​​​​​​​​​​​​​4 commits on 2026-06-15Mon, ​​​​​​​​​​​​​​​​​​​​​​​9 commits on 2026-06-22Mon, ​​​​​​​​​​​​​​​​​​​​​​​​13 commits on 2026-06-29Mon, ​​​​​​​​​​​​​​​​​​​​​​​​​
Tue10 commits on 2026-01-06Tue, Jan14 commits on 2026-01-13Tue, ​15 commits on 2026-01-20Tue, ​​12 commits on 2026-01-27Tue, ​​​8 commits on 2026-02-03Tue, Feb​​​​4 commits on 2026-02-10Tue, ​​​​​3 commits on 2026-02-17Tue, ​​​​​​6 commits on 2026-02-24Tue, ​​​​​​​10 commits on 2026-03-03Tue, Mar​​​​​​​​14 commits on 2026-03-10Tue, ​​​​​​​​​Tue, ​​​​​​​​​​: no dataTue, ​​​​​​​​​​​: no data8 commits on 2026-03-31Tue, ​​​​​​​​​​​​4 commits on 2026-04-07Tue, Apr​​​​​​​​​​​​​3 commits on 2026-04-14Tue, ​​​​​​​​​​​​​​5 commits on 2026-04-21Tue, ​​​​​​​​​​​​​​​10 commits on 2026-04-28Tue, ​​​​​​​​​​​​​​​​14 commits on 2026-05-05Tue, May​​​​​​​​​​​​​​​​​15 commits on 2026-05-12Tue, ​​​​​​​​​​​​​​​​​​13 commits on 2026-05-19Tue, ​​​​​​​​​​​​​​​​​​​9 commits on 2026-05-26Tue, ​​​​​​​​​​​​​​​​​​​​5 commits on 2026-06-02Tue, ​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-09Tue, Jun​​​​​​​​​​​​​​​​​​​​​​5 commits on 2026-06-16Tue, ​​​​​​​​​​​​​​​​​​​​​​​9 commits on 2026-06-23Tue, ​​​​​​​​​​​​​​​​​​​​​​​​13 commits on 2026-06-30Tue, ​​​​​​​​​​​​​​​​​​​​​​​​​
Wed11 commits on 2026-01-07Wed, Jan14 commits on 2026-01-14Wed, ​15 commits on 2026-01-21Wed, ​​12 commits on 2026-01-28Wed, ​​​7 commits on 2026-02-04Wed, Feb​​​​4 commits on 2026-02-11Wed, ​​​​​3 commits on 2026-02-18Wed, ​​​​​​6 commits on 2026-02-25Wed, ​​​​​​​11 commits on 2026-03-04Wed, Mar​​​​​​​​14 commits on 2026-03-11Wed, ​​​​​​​​​Wed, ​​​​​​​​​​: no dataWed, ​​​​​​​​​​​: no data8 commits on 2026-04-01Wed, ​​​​​​​​​​​​4 commits on 2026-04-08Wed, Apr​​​​​​​​​​​​​3 commits on 2026-04-15Wed, ​​​​​​​​​​​​​​6 commits on 2026-04-22Wed, ​​​​​​​​​​​​​​​10 commits on 2026-04-29Wed, ​​​​​​​​​​​​​​​​14 commits on 2026-05-06Wed, May​​​​​​​​​​​​​​​​​15 commits on 2026-05-13Wed, ​​​​​​​​​​​​​​​​​​12 commits on 2026-05-20Wed, ​​​​​​​​​​​​​​​​​​​8 commits on 2026-05-27Wed, ​​​​​​​​​​​​​​​​​​​​4 commits on 2026-06-03Wed, ​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-10Wed, Jun​​​​​​​​​​​​​​​​​​​​​​5 commits on 2026-06-17Wed, ​​​​​​​​​​​​​​​​​​​​​​​10 commits on 2026-06-24Wed, ​​​​​​​​​​​​​​​​​​​​​​​​14 commits on 2026-07-01Wed, ​​​​​​​​​​​​​​​​​​​​​​​​​
Thu12 commits on 2026-01-08Thu, Jan15 commits on 2026-01-15Thu, ​14 commits on 2026-01-22Thu, ​​11 commits on 2026-01-29Thu, ​​​7 commits on 2026-02-05Thu, Feb​​​​3 commits on 2026-02-12Thu, ​​​​​3 commits on 2026-02-19Thu, ​​​​​​7 commits on 2026-02-26Thu, ​​​​​​​11 commits on 2026-03-05Thu, Mar​​​​​​​​15 commits on 2026-03-12Thu, ​​​​​​​​​Thu, ​​​​​​​​​​: no dataThu, ​​​​​​​​​​​: no data7 commits on 2026-04-02Thu, ​​​​​​​​​​​​4 commits on 2026-04-09Thu, Apr​​​​​​​​​​​​​3 commits on 2026-04-16Thu, ​​​​​​​​​​​​​​6 commits on 2026-04-23Thu, ​​​​​​​​​​​​​​​11 commits on 2026-04-30Thu, ​​​​​​​​​​​​​​​​14 commits on 2026-05-07Thu, May​​​​​​​​​​​​​​​​​15 commits on 2026-05-14Thu, ​​​​​​​​​​​​​​​​​​12 commits on 2026-05-21Thu, ​​​​​​​​​​​​​​​​​​​7 commits on 2026-05-28Thu, ​​​​​​​​​​​​​​​​​​​​4 commits on 2026-06-04Thu, ​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-11Thu, Jun​​​​​​​​​​​​​​​​​​​​​​6 commits on 2026-06-18Thu, ​​​​​​​​​​​​​​​​​​​​​​​11 commits on 2026-06-25Thu, ​​​​​​​​​​​​​​​​​​​​​​​​14 commits on 2026-07-02Thu, ​​​​​​​​​​​​​​​​​​​​​​​​​
Fri12 commits on 2026-01-09Fri, Jan15 commits on 2026-01-16Fri, ​14 commits on 2026-01-23Fri, ​​11 commits on 2026-01-30Fri, ​​​6 commits on 2026-02-06Fri, Feb​​​​3 commits on 2026-02-13Fri, ​​​​​4 commits on 2026-02-20Fri, ​​​​​​7 commits on 2026-02-27Fri, ​​​​​​​12 commits on 2026-03-06Fri, Mar​​​​​​​​15 commits on 2026-03-13Fri, ​​​​​​​​​Fri, ​​​​​​​​​​: no dataFri, ​​​​​​​​​​​: no data6 commits on 2026-04-03Fri, ​​​​​​​​​​​​3 commits on 2026-04-10Fri, Apr​​​​​​​​​​​​​4 commits on 2026-04-17Fri, ​​​​​​​​​​​​​​7 commits on 2026-04-24Fri, ​​​​​​​​​​​​​​​12 commits on 2026-05-01Fri, ​​​​​​​​​​​​​​​​15 commits on 2026-05-08Fri, May​​​​​​​​​​​​​​​​​14 commits on 2026-05-15Fri, ​​​​​​​​​​​​​​​​​​11 commits on 2026-05-22Fri, ​​​​​​​​​​​​​​​​​​​7 commits on 2026-05-29Fri, ​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-05Fri, ​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-12Fri, Jun​​​​​​​​​​​​​​​​​​​​​​7 commits on 2026-06-19Fri, ​​​​​​​​​​​​​​​​​​​​​​​11 commits on 2026-06-26Fri, ​​​​​​​​​​​​​​​​​​​​​​​​14 commits on 2026-07-03Fri, ​​​​​​​​​​​​​​​​​​​​​​​​​
Sat3 commits on 2026-01-10Sat, Jan4 commits on 2026-01-17Sat, ​4 commits on 2026-01-24Sat, ​​2 commits on 2026-01-31Sat, ​​​1 commits on 2026-02-07Sat, Feb​​​​0 commits on 2026-02-14Sat, ​​​​​0 commits on 2026-02-21Sat, ​​​​​​2 commits on 2026-02-28Sat, ​​​​​​​3 commits on 2026-03-07Sat, Mar​​​​​​​​4 commits on 2026-03-14Sat, ​​​​​​​​​Sat, ​​​​​​​​​​: no dataSat, ​​​​​​​​​​​: no data1 commits on 2026-04-04Sat, ​​​​​​​​​​​​0 commits on 2026-04-11Sat, Apr​​​​​​​​​​​​​0 commits on 2026-04-18Sat, ​​​​​​​​​​​​​​2 commits on 2026-04-25Sat, ​​​​​​​​​​​​​​​3 commits on 2026-05-02Sat, ​​​​​​​​​​​​​​​​4 commits on 2026-05-09Sat, May​​​​​​​​​​​​​​​​​4 commits on 2026-05-16Sat, ​​​​​​​​​​​​​​​​​​3 commits on 2026-05-23Sat, ​​​​​​​​​​​​​​​​​​​1 commits on 2026-05-30Sat, ​​​​​​​​​​​​​​​​​​​​0 commits on 2026-06-06Sat, ​​​​​​​​​​​​​​​​​​​​​0 commits on 2026-06-13Sat, Jun​​​​​​​​​​​​​​​​​​​​​​1 commits on 2026-06-20Sat, ​​​​​​​​​​​​​​​​​​​​​​​3 commits on 2026-06-27Sat, ​​​​​​​​​​​​​​​​​​​​​​​​Sat, ​​​​​​​​​​​​​​​​​​​​​​​​​: no data

a monday first week

The same grid for a reader whose week starts on Monday, and in that reader's own words. weekStartsOn rotates the rows; weekdayLabels and monthLabels translate them. The two are separate props on purpose: the labels array is always Sunday-first whatever the grid does, so a Monday-first German calendar and a Monday-first English one share the same convention and differ only in the strings. The domain is pinned, which is what makes two calendars comparable — on their own domains a quiet year and a busy one look identical.

Beiträge pro Tag
Beiträge pro Tag
RowJan​​​​​Feb​​​​​​​​​​​​​​​​​​​​​​Mär​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
Mo0 Beiträge am 2026-01-05Mo, Jan10 Beiträge am 2026-01-12Mo, ​7 Beiträge am 2026-01-19Mo, ​​4 Beiträge am 2026-01-26Mo, ​​​1 Beiträge am 2026-02-02Mo, Feb​​​​11 Beiträge am 2026-02-09Mo, ​​​​​8 Beiträge am 2026-02-16Mo, ​​​​​​5 Beiträge am 2026-02-23Mo, ​​​​​​​2 Beiträge am 2026-03-02Mo, Mär​​​​​​​​12 Beiträge am 2026-03-09Mo, ​​​​​​​​​9 Beiträge am 2026-03-16Mo, ​​​​​​​​​​6 Beiträge am 2026-03-23Mo, ​​​​​​​​​​​3 Beiträge am 2026-03-30Mo, ​​​​​​​​​​​​
Di7 Beiträge am 2026-01-06Di, Jan4 Beiträge am 2026-01-13Di, ​1 Beiträge am 2026-01-20Di, ​​11 Beiträge am 2026-01-27Di, ​​​8 Beiträge am 2026-02-03Di, Feb​​​​5 Beiträge am 2026-02-10Di, ​​​​​2 Beiträge am 2026-02-17Di, ​​​​​​12 Beiträge am 2026-02-24Di, ​​​​​​​9 Beiträge am 2026-03-03Di, Mär​​​​​​​​6 Beiträge am 2026-03-10Di, ​​​​​​​​​3 Beiträge am 2026-03-17Di, ​​​​​​​​​​0 Beiträge am 2026-03-24Di, ​​​​​​​​​​​10 Beiträge am 2026-03-31Di, ​​​​​​​​​​​​
Mi1 Beiträge am 2026-01-07Mi, Jan11 Beiträge am 2026-01-14Mi, ​8 Beiträge am 2026-01-21Mi, ​​5 Beiträge am 2026-01-28Mi, ​​​2 Beiträge am 2026-02-04Mi, Feb​​​​12 Beiträge am 2026-02-11Mi, ​​​​​9 Beiträge am 2026-02-18Mi, ​​​​​​6 Beiträge am 2026-02-25Mi, ​​​​​​​3 Beiträge am 2026-03-04Mi, Mär​​​​​​​​0 Beiträge am 2026-03-11Mi, ​​​​​​​​​10 Beiträge am 2026-03-18Mi, ​​​​​​​​​​7 Beiträge am 2026-03-25Mi, ​​​​​​​​​​​4 Beiträge am 2026-04-01Mi, ​​​​​​​​​​​​
Do8 Beiträge am 2026-01-08Do, Jan5 Beiträge am 2026-01-15Do, ​2 Beiträge am 2026-01-22Do, ​​12 Beiträge am 2026-01-29Do, ​​​9 Beiträge am 2026-02-05Do, Feb​​​​6 Beiträge am 2026-02-12Do, ​​​​​3 Beiträge am 2026-02-19Do, ​​​​​​0 Beiträge am 2026-02-26Do, ​​​​​​​10 Beiträge am 2026-03-05Do, Mär​​​​​​​​7 Beiträge am 2026-03-12Do, ​​​​​​​​​4 Beiträge am 2026-03-19Do, ​​​​​​​​​​1 Beiträge am 2026-03-26Do, ​​​​​​​​​​​11 Beiträge am 2026-04-02Do, ​​​​​​​​​​​​
Fr2 Beiträge am 2026-01-09Fr, Jan12 Beiträge am 2026-01-16Fr, ​9 Beiträge am 2026-01-23Fr, ​​6 Beiträge am 2026-01-30Fr, ​​​3 Beiträge am 2026-02-06Fr, Feb​​​​0 Beiträge am 2026-02-13Fr, ​​​​​10 Beiträge am 2026-02-20Fr, ​​​​​​7 Beiträge am 2026-02-27Fr, ​​​​​​​4 Beiträge am 2026-03-06Fr, Mär​​​​​​​​1 Beiträge am 2026-03-13Fr, ​​​​​​​​​11 Beiträge am 2026-03-20Fr, ​​​​​​​​​​8 Beiträge am 2026-03-27Fr, ​​​​​​​​​​​5 Beiträge am 2026-04-03Fr, ​​​​​​​​​​​​
Sa9 Beiträge am 2026-01-10Sa, Jan6 Beiträge am 2026-01-17Sa, ​3 Beiträge am 2026-01-24Sa, ​​0 Beiträge am 2026-01-31Sa, ​​​10 Beiträge am 2026-02-07Sa, Feb​​​​7 Beiträge am 2026-02-14Sa, ​​​​​4 Beiträge am 2026-02-21Sa, ​​​​​​1 Beiträge am 2026-02-28Sa, ​​​​​​​11 Beiträge am 2026-03-07Sa, Mär​​​​​​​​8 Beiträge am 2026-03-14Sa, ​​​​​​​​​5 Beiträge am 2026-03-21Sa, ​​​​​​​​​​2 Beiträge am 2026-03-28Sa, ​​​​​​​​​​​12 Beiträge am 2026-04-04Sa, ​​​​​​​​​​​​
So3 Beiträge am 2026-01-11So, Jan0 Beiträge am 2026-01-18So, ​10 Beiträge am 2026-01-25So, ​​7 Beiträge am 2026-02-01So, ​​​4 Beiträge am 2026-02-08So, Feb​​​​1 Beiträge am 2026-02-15So, ​​​​​11 Beiträge am 2026-02-22So, ​​​​​​8 Beiträge am 2026-03-01So, ​​​​​​​5 Beiträge am 2026-03-08So, Mär​​​​​​​​2 Beiträge am 2026-03-15So, ​​​​​​​​​12 Beiträge am 2026-03-22So, ​​​​​​​​​​9 Beiträge am 2026-03-29So, ​​​​​​​​​​​6 Beiträge am 2026-04-05So, ​​​​​​​​​​​​

Accessibility

  • The grid is a real <table>, so a screen reader walks the same structure the eye reads: a header row, a header column, and a cell that announces its own reading.
  • A day with no entry announces “no data” rather than a number, so a gap and a zero are different to a reader who cannot see the ramp.
  • The reading is keyed by the cell, so the date is announced with the count — the row and column headers alone name a weekday and a month, not a day.