Heatmap Calendar
Pro8 premium color-palette variants with interactive tooltips, shape options, stats badges and full dark-mode support.
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
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Custom palette + stats
ProWhen 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
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the activity are being fetched. |
| error | SvDataError | string | null | null | Load failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`. |
| emptyMessage | string | 'No activity recorded' | Copy for the no-data state. |
| filtered | boolean | false | True when the emptiness is caused by a filter rather than an empty set. |
| data | HeatmapDay[] | [] | Daily values: { date, value }. |
| variant | HeatmapVariant | 'github' | Color palette variant (github, gitlab, fire, ocean…). |
| cellShape | HeatmapCellShape | 'rounded' | Cell shape: square or rounded. |
| weeks | number | 53 | Number of week columns to render. |
| title | string | '' | Heading title. |
| subtitle | string | '' | Subtitle under the title. |
| showMonthLabels | boolean | true | Show month labels along the top. |
| showDayLabels | boolean | true | Show weekday labels down the side. |
| showLegend | boolean | true | Show the color-scale legend. |
| showStats | boolean | true | Show summary stat badges. |
| maxValue | number | null | null | Value mapped to the most intense color (null = auto from data). |
| cellGap | number | 3 | Gap between cells in pixels. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| retry | void | The host should re-run the failed load. |
| dayClick | HeatmapDayClickEvent | Fires 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
ProBound to the names this component actually exposes.
Host class
ProDrive 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.