Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

HeatmapChart

  • Stable
  • WCAG 2.2 evidence
  • RTL

A heat map: cells coloured by value on the five-step heatmap ramp, with a legend of the ramp and its numeric ranges. Data driven: rows, columns and values (or days) in, SVG out; the same props render the static SVG on the server. Accessibility: the figure is named by title, described by summary and backed by a data table with every value (WCAG 1.1.1, 1.3.1). The value is never told by colour alone (1.4.1): the legend lists the numeric range of every step, cells can carry the number, and each cell is announced and shown in the tooltip with its row, column and value. The plot is ONE tab stop in a 2D grid: the arrow keys move one cell in both directions, Home and End go to the row's ends, Page Up and Page Down to the column's ends, Ctrl plus Home or End to the first and last cell; the tooltip shows on hover and focus, stays while hovered and closes with Escape (2.1.1, 1.4.13). The cells are img elements in a group, like the other charts, not an ARIA grid: the heat map is read-only data, and the data table is the real two-dimensional alternative with row and column headers; an ARIA grid on SVG is supported unevenly and would promise cell navigation that screen readers do not give. At a narrow width the cells keep a readable size and the plot scrolls inside a labelled, focusable region (1.4.10). The draw-in is behind motion-safe:; the plot stays left-to-right in right-to-left pages while the card, legend and table mirror, and digits and month and weekday names follow the locale. Consumer duties: a title that asks the question, a summary with the main message, units in valueFormat, thresholds that mean something. Contrast: the numbers on cells are 4.5:1 or better on every step except step 3 in the dark theme (4.4:1), and the lightest steps are under 3:1 against the card, which is why the value is also text.

import { HeatmapChart } from "@nexera-ui/react";
Loading example…
13
examples
28
props
4
live controls
1
platform
11
WCAG criteria
1
block uses it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
layout
valueLabels
title
description
Generated code
import { HeatmapChart } from "@nexera-ui/react";

<HeatmapChart />

Examples 12

The same examples as Storybook, rendered live. Open Code to copy one.

Calendar

The calendar layout at a normal card width: cells shrink to 10 px, then the plot scrolls inside a labelled, focusable region (Tab to it, then arrow keys scroll).

Loading example…

Calendar three weeks

A short calendar starting on a Sunday: three weeks, the weekday names in the page's language.

Loading example…

Value on every cell

Every cell shows its number (where it fits); the legend still lists the ranges, and the table has every value.

Loading example…

Custom thresholds

Meaningful bands: you set the four values where the ramp steps start, and the legend follows.

Loading example…

Missing values

Cells with no data are dashed outlines with their own legend entry, never a step of the ramp.

Loading example…

Single cell

One cell.

Loading example…

Large grid

A busy grid: seven days by 24 hours. The cells keep a readable width and the plot scrolls inside its region on a narrow card.

Loading example…

Long labels

Long row and column names: row labels widen the gutter, column labels thin out; the cell names, the tooltip and the table keep them whole.

Loading example…

Loading

Loading, empty and error are ChartStates inside the card; the header stays.

Loading example…

Empty

Loading example…

Error state

Loading example…

Right to left

Right-to-left page: the card, legend and table mirror, the grid keeps its left-to-right time axis (ArrowRight is still the next time slot), digits follow the locale.

Loading example…

Props 28

Press "Try it" on a card to load that prop into the playground.

28 props shown

layoutNexera
"grid" | "calendar"

The grid layout, the default. The calendar layout.

Default –
rowsNexera
readonly string[]

The names of the rows, from the top ("Mon", "Tue",...). Row labels sit at the start of the plot.

Default –
columnsNexera
readonly string[]

The names of the columns, from the start ("7:00", "7:30",...). Labels that do not fit are thinned out.

Default –
valuesNexera
readonly (readonly (number | null)[])[]

The values: values[row][column]. null, or a missing entry, is no data and draws a dashed outline instead of a step of the ramp.

Default –
heightNexera
number

Height of the plot in px, divided among the rows.

Default 24 plus 33.6 per row plus 7 between rows (Figma `Plot`: 220 for five rows)
daysNexera
readonly HeatmapDay[]

The days, in any order, each with a yyyy-mm-dd date and a value. The calendar runs from the week of the first day to the week of the last; a day in between that is not listed is no data. A date that is not a real date is skipped.

Default –
weekStartNexera
0 | 2 | 4 | 1 | 3 | 5 | 6

The weekday the rows start with: 0 is Sunday, 1 Monday, 6 Saturday.

Default 1
valueLabelNexera
string

Words for the value in the tooltip and the point labels, and the header of the value column of a calendar's table ("Check-ins", "Hours"). Translate it.

Default Value
valueLabelsNexera
"none" | "high" | "all"

Numbers on the cells: high labels the two darkest steps of the ramp, all every cell, none none. A number is only drawn where it fits the cell, so a calendar of small cells shows none. The value is also in the tooltip, the point labels and the table, so it is never told by colour alone (WCAG 1.4.1).

Default high
domainNexera
readonly [number, number]

The lower and upper edge of the ramp. Values at or below the lower edge are step 1, the upper edge is step 5.

Default 0 (or the smallest value when that is negative) to the largest value
thresholdsNexera
readonly [number, number, number, number]

The four values where the ramp steps 2 to 5 start, ascending (use them for meaningful bands: 10, 20, 30, 40). The legend shows the ranges they make.

Default five equal steps over `domain`, rounded to whole numbers for whole-number data
lessLabelNexera
string

The word at the low end of the legend ramp. Translate it.

Default Less
moreLabelNexera
string

The word at the high end of the legend ramp. Translate it.

Default More
scrollLabelNexera
string

Name of the scroll region that holds the plot when the container is too narrow for the cells. Translate it.

Default the plot label followed by ", scrollable"
title*Nexera
string

Chart title: the question the chart answers ("Headcount"). Required: it names the figure, the plot and the data table (WCAG 1.1.1).

Default –
descriptionNexera
ReactNode

Secondary line under the title.

Default –
summary*Nexera
string

One or two sentences with what the chart shows and its main message ("Headcount grew from 96 to 128 over twelve months"). Required: it describes the figure for assistive technology (WCAG 1.1.1); the data table has the details.

Default –
rangeNexera
ChartRangeProps

Range switch in the header: 3M, 6M, 12M. Pass the data of the chosen range back in.

Default –
actionsNexera
ReactNode

Extra controls in the header, after the range switch.

Default –
kpiNexera
ChartKpiProps

KPI row above the plot: the headline number with an optional label or change badge.

Default –
stateNexera
ChartPlotState

The state that replaces the plot: loading (skeleton), empty or error. A chart without a value to plot shows the empty state by itself; pass { status: "empty", title, description, action } to give it your wording.

Default –
tableNexera
ChartTableOptions

The data table that is the text alternative: caption, first-column header and whether it is visible or only for assistive technology.

Default –
localeNexera
string

Locale of digits and separators.

Default the `NexeraProvider` locale
valueFormatNexera
NumberFormatOptions

Intl.NumberFormat options for values ({ style: "currency", currency: "PKR" }, { style: "percent" }). Serialisable, so it works from a Server Component; formatValue needs a Client Component.

Default –
formatValueNexera
(value: number) => string

Formats a value for tooltips, point labels and the table (full precision). Wins over valueFormat.

Default –
formatAxisValueNexera
(value: number) => string

Formats an axis tick (short: "29M").

Default the compact notation of `valueFormat`
plotLabelNexera
string

Accessible name of the plot group. Translate it.

Default the chart `title`
noDataLabelNexera
string

Text for a missing value in the tooltip and the table. Translate it.

Default No data

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

8 direct · 3 supporting
  • 1.1.1Non-text ContentLevel A · tested directly
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.4.1Use of ColorLevel A · tested directly
  • 1.4.3Contrast (Minimum)Level AA · supporting test
  • 1.4.10ReflowLevel AA · tested directly
  • 1.4.13Content on Hover or FocusLevel AA · tested directly
  • 2.1.1KeyboardLevel A · tested directly
  • 2.3.3Animation from InteractionsLevel AAA · supporting test
  • 2.4.7Focus VisibleLevel AA · supporting test
  • 4.1.2Name, Role, ValueLevel A · tested directly
  • 4.1.3Status MessagesLevel AA · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

Usage
<HeatmapChart className="shadow-sm" />

Used in blocks

Related components