Heatmap Calendar

Pro

8 premium color-palette variants with interactive tooltips, shape options, stats badges and full dark-mode support.

</>sv-heatmap-calendar heatmapcalendaractivity

Complexity tier: Primitive Presents a value: held to semantic markup and contrast, with its right-to-left and print gaps recorded and the right-to-left debt allowed only to shrink.

import { SvHeatmapCalendarComponent } from '@styloviz-pro/display';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Custom palette + stats

Pro

When to use

  • Visualizing daily activity/intensity over weeks or a year (contributions, usage).
  • You want a GitHub-style calendar with a color scale and tooltips.
  • For arbitrary X/Y matrices use the Heatmap Chart instead.

Async states

  • loading
  • empty
  • error
  • retry

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the activity are being fetched.
errorSvDataError | string | nullnullLoad failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`.
emptyMessagestring'No activity recorded'Copy for the no-data state.
filteredbooleanfalseTrue when the emptiness is caused by a filter rather than an empty set.
dataHeatmapDay[][]Daily values: { date, value }.
variantHeatmapVariant'github'Color palette variant (github, gitlab, fire, ocean…).
cellShapeHeatmapCellShape'rounded'Cell shape: square or rounded.
weeksnumber53Number of week columns to render.
titlestring''Heading title.
subtitlestring''Subtitle under the title.
showMonthLabelsbooleantrueShow month labels along the top.
showDayLabelsbooleantrueShow weekday labels down the side.
showLegendbooleantrueShow the color-scale legend.
showStatsbooleantrueShow summary stat badges.
maxValuenumber | nullnullValue mapped to the most intense color (null = auto from data).
cellGapnumber3Gap between cells in pixels.

Outputs

EventPayload typeDescription
retryvoidThe host should re-run the failed load.
dayClickHeatmapDayClickEventFires when a day with a non-zero value is clicked or activated with Enter/Space. Payload is the `HeatmapDay` and its local-midnight `Date`; empty and zero-value days do not emit.

Wire it to your API

This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.

Template

Pro

Bound to the names this component actually exposes.

Host class

Pro

Drive the three async inputs from your own fetch.

  • This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `data`, `loading` and `error`.
  • Set `filtered` when a search or filter is active. It is the difference between "you have no orders" and "no orders match this filter" — telling a customer with 4,000 orders the first one reads as a bug.
  • Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.

Full walkthrough: Connecting to a backend.

Customization & theming

  • Eight palettes (GitHub, GitLab, fire, ocean…).
  • Square or rounded cells with configurable scale.
  • Optional stats badges and tooltips.

Best practices

  • Do: Set a sensible `maxValue` so the color scale isn't skewed by one outlier.
  • Do: Pair the color scale with tooltips/legend so values are readable.
  • Tip: Choose a palette with enough contrast in both light and dark themes.

Accessibility

  • The value reaches the page as a colour step and nothing else (WCAG 1.4.1), so the calendar publishes a table beside it — one row per MONTH, not per day, with the total, the active-day count and the busiest day. A day's own value is already reachable through its cell button; what is not reachable is the SHAPE, which is the only thing 371 squares say and is said entirely by their arrangement. A 371-row table would restate what is already there and still not answer it.
  • Empty months stay in the table. A gap is a fact about the year — the pale band the picture shows as a quiet stretch — and dropping those rows would hide exactly what the shape is for.
  • The table describes the window that is drawn, and the streak/total figures above it are counted over the same window, so scrolling to a different year cannot leave the numbers describing the old one.
  • Active days are focusable buttons that expose their date and value, and activate on Enter/Space.
  • Tooltips appear on hover and on keyboard focus; the grid is a labelled group and empty days are hidden from assistive tech.
  • Color scale is paired with text values in the tooltip, so meaning is not conveyed by color alone.

Feedback on Heatmap Calendar

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.