Heatmap
1,749 contributions
September 15, 2026: 10 contributions
Installation
npx @mielui/svelte add heatmapyarn dlx @mielui/svelte add heatmapbunx @mielui/svelte add heatmapUsage
Pass daily counts with dates in YYYY-MM-DD format. Root renders the complete calendar when it has no children. No GitHub connection is required.
<script lang="ts">
import * as Heatmap from '@mielui/svelte/components/heatmap';
const days = [
{
date: '2026-09-14',
count: 4
},
{
date: '2026-09-15',
count: 12
}
];
</script>
<Heatmap.Root {days} endDate="2026-09-15" weeks={12} />Examples
Custom composition
This example omits weekday labels, moves the legend before the detail, and reads the same total as Summary. Tooltip follows the hovered or focused cell. Select a day with Enter, Space, or a click.
September 15, 2026: 10 contributions
Choose a day
Changing the range
Keep the reporting end date fixed while switching the number of visible weeks. Summary counts only dates in that range. On narrow screens, the calendar scrolls horizontally.
825 contributions
September 15, 2026: 10 contributions
Data and animation states
Set loading while fetching activity. An empty days array shows the empty calendar, while days with zero counts stay ready. Both states keep the calendar layout and turn off inspection.
1,749 contributions
September 15, 2026: 10 contributions
Without a tooltip
The automatic layout includes Tooltip. In a custom layout, omit it to keep native browser titles instead. Every cell keeps its accessible date and count label.
<Heatmap.Root {days} weeks={12} endDate="2026-09-15">
<Heatmap.Calendar>
<Heatmap.MonthLabels />
<Heatmap.WeekdayLabels />
<Heatmap.Grid />
</Heatmap.Calendar>
<Heatmap.Detail />
</Heatmap.Root>Data and range
Root takes days, loading, weeks, endDate, weekStartsOn, locale, animation, and onDaySelect. weeks defaults to 26 and accepts 1 to 104. weekStartsOn defaults to 0, Sunday, and accepts 0 through 6. locale formats month and weekday names and defaults to en-US.
Dates use UTC. Input order does not matter, missing dates count as zero, and the last entry wins when a date repeats. endDate defaults to the latest supplied date, or today for an empty dataset; set it for a stable reporting period.
The calendar starts at the beginning of the first week and stops at endDate. Totals include only visible dates. Counts must be finite and non-negative. An optional level from 0 to 4 sets a day's intensity; otherwise intensity follows the largest visible count. Invalid values throw a RangeError.
Animation
animation defaults to rows. Choose columns for a left-to-right stagger, live for a repeating column highlight, or none to render immediately. Live motion keeps the counts unchanged and pauses during inspection, offscreen, and in hidden documents. Entrance timing follows the theme's motion setting, and reduced motion skips the entrance.
Parts
Root owns the data and passes days and total to its children snippet. Header, Calendar, and Footer arrange content. Summary passes its total to a children snippet. Grid passes the computed days to a children snippet; render a Cell for each. Detail passes the active day to a children snippet.
MonthLabels, WeekdayLabels, and Legend render default labels that children can replace. Each part accepts native attributes and class. Keep Grid inside Calendar so the month and weekday labels line up.
Keyboard and accessibility
Tab enters the calendar once. Arrow keys move between dates, Home focuses the first visible date, and End the last. Left and right follow the layout in RTL. Each cell announces its full date and count, so color is not the only source of information.
Hover or focus updates Detail and opens Tooltip; Escape closes the tooltip. Activating a cell calls onDaySelect with the computed day.
Labels
Built-in text is English. Pass a labels object to Root to translate the unit in cell labels and the summary (unit, a function of the count), the tooltip heading (tooltipValue), the legend ends (less, more), the grid's accessible name in each state (grid, gridLoading, gridEmpty), the detail line while loading or empty (detailLoading, detailEmpty), and the summary before data is ready (summaryPending). HeatmapLabels types it; every key is optional.
<Heatmap.Root
{days}
labels={{
unit: (count) => (count === 1 ? 'commit' : 'commits'),
less: 'Moins',
more: 'Plus'
}}
/>API reference
Heatmap.Root
labelsHeatmapLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
daysRequiredreadonly Day[]Daily counts keyed by ISO date. Missing dates count as zero.
weeksnumberNumber of weeks shown, from 1 to 104.
Default
26loadingbooleanShows the loading state in place of the content.
Default
falseanimation"rows" | "columns" | "live" | "none"rowsandcolumnsstagger the entrance,liverepeats a column highlight, andnoneis static.Default
'rows'endDatestringLast date shown. Defaults to the latest supplied date, or today for an empty dataset.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6First day of each week, from 0 (Sunday) to 6.
Default
0localestringLocale for month and weekday names.
Default
'en-US'onDaySelect((day: Cell) => void)Called with the computed day when a cell is activated.
childrenSnippet<[{ days: readonly Cell[]; total: number; }]>Custom layout. Omit it for the built-in calendar, receiving the visible days and their total.
Heatmap.Cell
dayRequired{ date: string; count: number; level: number; column: number; row: number; label: string; }Visible day this cell represents.
Heatmap.Detail
childrenSnippet<[Cell | undefined]>Renders the detail line for the hovered or focused day.
Heatmap.Grid
childrenSnippet<[readonly Cell[]]>Renders the cells. Omit it for one Cell per visible day.
Heatmap.Summary
childrenSnippet<[number]>Renders the summary from the total of the visible days.
Other parts
These parts have no props of their own. They pass HTML attributes and events to their element.
Heatmap.CalendarHeatmap.FooterHeatmap.HeaderHeatmap.LegendHeatmap.MonthLabelsHeatmap.TooltipHeatmap.WeekdayLabels
pnpm dlx @mielui/svelte add heatmap