Skip to content
WANCRAFT

G.26Data & Feedback

Activity Heatmap

A contribution-style calendar heatmap with keyboard navigation and focus-aware tooltips.

ReactTailwindCSSintermediate

Overview

Activity Heatmap lays out daily counts as week columns, colour-mixing your accent into five levels. Dates are handled as UTC day numbers so cells never drift across time zones, and the range comes from your data (or explicit start/end dates). The grid is a real ARIA grid: one roving tab stop, arrow keys between days, Home/End along a row, and every cell carries a full label such as “12 contributions on 3 Oct 2026”. The same tooltip appears on hover and on keyboard focus, and the layout either fits its container or scrolls horizontally with the latest weeks in view.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/activity-heatmap.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/activity-heatmap.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/activity-heatmap.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
1 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { ActivityHeatmap, type HeatmapDatum } from "@/components/ui/activity-heatmap";

export function ActivityHeatmapExample() {
  // Replace with your own daily counts ("YYYY-MM-DD").
  const data: HeatmapDatum[] = Array.from({ length: 365 }, (_, i) => ({
    date: new Date(Date.UTC(2025, 9, 4) + i * 86_400_000).toISOString().slice(0, 10),
    count: (i * 7 + (i % 5) * 3) % 13,
  }));

  return (
    <ActivityHeatmap data={data} />
  );
}

03Props

PropTypeDefaultDescription
data{ date: string; count: number }[]—Daily counts. Dates are "YYYY-MM-DD"; duplicates are summed and negative counts treated as 0.
accentstring"#FF7448"Colour of the top level; lower levels mix it toward transparent.
weekStart"sunday" | "monday""sunday"Weekday shown in the first row.
layout"fit" | "scroll""fit"Scale cells to the container, or keep cellSize and scroll horizontally (latest weeks in view).
cellSizenumber12Cell size in px for the scroll layout.
gapnumber3Gap between cells in px.
radiusnumber2Cell corner radius in px.
showMonthLabelsbooleantrueMonth names above the first week of each month.
showWeekdayLabelsbooleantrueAlternate weekday names beside the rows.
showLegendbooleantrueTotal, range and the Less → More scale.
labelstring"Activity"Accessible name of the grid.
unitstring"contribution"Singular unit used in labels and tooltips.
unitPluralstring—Plural unit (defaults to unit + "s").
startDatestring—First day shown; defaults to the earliest date in data.
endDatestring—Last day shown; defaults to the latest date in data.
localestring"en-GB"Locale for dates and numbers.

04Features

  • 01Five-level colour scale derived from a single accent
  • 02Time-zone-safe UTC date handling
  • 03Fit-to-width or horizontally scrolling layout
  • 04Configurable week start, month and weekday labels
  • 05One tooltip for hover and keyboard focus
input · hoverinput · keyboardinput · focus

05Accessibility

  • Rendered as role="grid" with rows and gridcells; a single roving tab stop starts on the most recent day.
  • Arrow keys move between days (skipping out-of-range padding), Home/End jump along the row, Escape hides the tooltip.
  • Each cell has an aria-label like “12 contributions on 3 Oct 2026”; a visually hidden summary (total, range, busiest day) describes the grid.
  • Colour is never the only signal: counts are available as text in labels and tooltips.