On this page
Import
import { CalendarHeatmap } from '@envsemble/envui';
Usage
CalendarHeatmap takes data, one entry per day with its date, as YYYY-MM-DD, its value, which chooses the color step, and a label with the value in words and its unit, such as 4 deployments. Days without an entry count as 0. startDate and endDate set the days shown, from the earliest to the latest day in data by default. Name the grid with aria-label, or aria-labelledby for a visible heading.
import { CalendarHeatmap, type CalendarHeatmapDay } from '@envsemble/envui';
/** Stands in for a year of deployment counts: busier midweek, with quiet stretches. */
function deploymentsPerDay(): CalendarHeatmapDay[] {
const end = Date.UTC(2026, 2, 31);
return Array.from({ length: 365 }, (_, index) => {
const time = end - (364 - index) * 86_400_000;
const weekday = new Date(time).getUTCDay();
const wave = Math.sin(index / 9) + Math.sin((index * 5) / 23) + 0.6;
const count = Math.max(0, Math.round(wave * 3 * (weekday === 0 || weekday === 6 ? 0.3 : 1)));
return {
date: new Date(time).toISOString().slice(0, 10),
value: count,
label: `${count} ${count === 1 ? 'deployment' : 'deployments'}`,
};
});
}
const data = deploymentsPerDay();
export default function Deployments() {
return <CalendarHeatmap aria-label="Deployments in the last year" data={data} tone="success" />;
}Tones and color steps
tone is primary, the default, accent, success, warning, danger, done or neutral: the tone the colors are mixed from. levels sets the color steps, the empty one included, from 2 to 10, and 5 by default; maxValue sets the value that takes the strongest color, the largest value shown by default.
Color by rank
thresholds sets the lowest value of each color step above the empty one, in ascending order, up to nine, such as quantiles of the data, as ColorByRank computes them; they replace levels and maxValue.
<CalendarHeatmap aria-label="Edits by rank" data={data} thresholds={[1, 3, 5, 8]} />
Tooltip
renderTooltip receives the day, with its date, value, label and level, the color step from 0, and returns the tooltip's content; the day's accessible name keeps its date and value. formatValue and formatDate write a value and a date.
<CalendarHeatmap
aria-label="Reviews in ten weeks"
data={data}
formatValue={reviews}
renderTooltip={({ date, value }) => (
<>
<strong>{reviews(value)}</strong>
<br />
{dates.format(new Date(`${date}T00:00:00Z`))}
</>
)}
/>
Languages
EnvUIProvider's locale names the months, weekdays and dates, through Intl; monthLabels, weekdayLabels, lessLabel and moreLabel set them for one heatmap. Weeks start on the locale's first day, as on Calendar; weekStart sets another, from 0 for Sunday to 6 for Saturday, such as weekStart={1} for Monday.
<EnvUIProvider messages={{ calendarHeatmap: { less: 'Quieter', more: 'Busier' } }}>
<CalendarHeatmap aria-label="Activity in the first quarter" data={data} weekStart={1} />
</EnvUIProvider>
Composition
The parts are the month names, env-calendar-heatmap-month, the weekday names, env-calendar-heatmap-weekday, the days, env-calendar-heatmap-day, and the legend, env-calendar-heatmap-legend, with a swatch, env-calendar-heatmap-swatch, for each step. The tooltip is env-calendar-heatmap-tooltip, the shared tooltip popup. Put the exact figures elsewhere, such as a Table, where people compare them.
Accessibility
You provide
- A name for the heatmap, and values whose names say their unit.
- The exact figures elsewhere, where people compare them.
envUI provides
- A read-only
gridwith a cell for each day, named with its date and value. - One tab stop, the tooltip on focus as on hover, and a focus outline.
- Month and weekday names and the legend hidden; each day's name says it all.
Props
CalendarHeatmap
A calendar of daily values with weeks as columns and weekdays as rows, colored in steps of a tone. Each day names its date and value, shows them in a tooltip on hover and focus, and the grid is one tab stop that the arrow keys move through.
| Prop | Type | Description |
|---|---|---|
datarequired | readonly CalendarHeatmapDay[ | Values by day; days without an entry count as 0. |
startDate | string | The first day shown, as YYYY-MM-DD; the earliest day in data by default. |
endDate | string | The last day shown, as YYYY-MM-DD; the latest day in data by default. |
levelsDefault 5 | number | Color steps including the empty step, 2 to 10; 5 by default. |
maxValue | number | The value that takes the strongest color; the largest value shown by default. |
thresholds | readonly number[ | The lowest value of each color step above the empty one, in ascending order, such as quantiles of the data to color by rank. Up to nine; they replace levels and maxValue. A day below the first threshold shows as empty, and a first threshold of 0 or less colors days of 0 too. |
weekStartDefault the locale's, or Monday where the browser cannot tell | 0123456 | The first day of each week column, from 0 for Sunday to 6 for Saturday, as on Calendar. |
toneDefault 'primary' | 'neutral''primary''accent''success''warning''danger''done' | The tone the colors are mixed from: primary by default. |
formatValueDefault the number format of EnvUIProvider's locale, or else the browser's | ( | Text for a value. |
formatDateDefault the weekday, day, month and year in the locale, such as Tue 14 Oct 2025 | ( | Text for a day's date, in its accessible name and the default tooltip. |
renderTooltip | ( | Tooltip content for a day; the date and value by default. |
monthLabelsDefault the locale's short month names, from Intl | readonly string[ | Twelve month names above the weeks, from January. |
weekdayLabelsDefault the locale's short weekday names, from Intl | readonly string[ | Seven weekday names beside the rows, from Sunday. |
lessLabelDefault 'Less' | string | Legend text before the lightest color. It overrides EnvUIProvider's `messages.calendarHeatmap.less`. |
moreLabelDefault 'More' | string | Legend text after the strongest color. It overrides EnvUIProvider's `messages.calendarHeatmap.more`. |
aria-label | string | Required when aria-labelledby is not set. Names the grid of days, such as "Deployments in the last year"; this or aria-labelledby. |
aria-labelledby | string | Required when aria-label is not set. The id of visible text that names the grid of days, such as a heading; this or aria-label. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
env-calendar-heatmap- The heatmap of days over months.
env-calendar-heatmap-corner- The empty corner above the weekday labels.
env-calendar-heatmap-day- One day's cell, filled by its level.
env-calendar-heatmap-grid- The grid of days.
env-calendar-heatmap-legend- The legend of levels.
env-calendar-heatmap-month- A month's label above the grid.
env-calendar-heatmap-pad- An empty cell outside the range.
env-calendar-heatmap-scroll- The region that scrolls the grid sideways.
env-calendar-heatmap-swatch- One level's swatch in the legend.
env-calendar-heatmap-tooltip- The tooltip of a day.
env-calendar-heatmap-tooltip-positioner- The tooltip's positioner.
env-calendar-heatmap-weekday- A weekday's label beside the grid.
data-closed- Any value, or present on env-calendar-heatmap-tooltip-positioner
data-date- Any value, or present on env-calendar-heatmap-day
data-day- Any value, or present on env-calendar-heatmap-day
data-level- Any value, or present on env-calendar-heatmap-day, env-calendar-heatmap-swatch
data-toneaccent·danger·done·neutral·primary·success·warning
Strings
EnvUIProvider's messages overrides each, and a component's own label prop wins over it.
messages.calendarHeatmap.less"Less"The low end of the legend.messages.calendarHeatmap.more"More"The high end of the legend.
Changelog
- 1.0.0
formatTooltipisrenderTooltip, as it returns content, asrender*callbacks do; Weeks start on the locale's first day, as on Calendar, andweekStarttakes any weekday; they started on Sunday. A date that doesn't exist, such as 2026-02-31, is left out and reported while developing, where it moved to the next month.Month and weekday names, dates and numbers follow the locale, from
Intl, and the legend comes frommessages.calendarHeatmap; the tooltip is the shared tooltip popup.HeatmapisCalendarHeatmap, withCalendarHeatmapDay,CalendarHeatmapCelland theenv-calendar-heatmap-*classes; the page iscalendar-heatmap.