All charts

heatmap/*

Heatmap

Heatmaps — density / activity over a 2D grid. Composed from SVG primitives wrapped in ChartContainer (recharts has no native heatmap).

2 variants
@vireya/ui/charts/heatmap/calendar

GitHub-style 53×7 calendar heatmap. SVG grid + color-mix intensity off the active accent token, with native <title> tooltips.

client
W0W5W10W15W20W25W30W35W40W45W50MonWedFri0 · 0: No activity0 · 1: No activity0 · 2: No activity0 · 3: No activity0 · 4: No activity0 · 5: 1 contribution0 · 6: No activity0 · 7: 2 contributions0 · 8: 4 contributions0 · 9: No activity0 · 10: 4 contributions0 · 11: 2 contributions0 · 12: No activity0 · 13: No activity0 · 14: 1 contribution0 · 15: 3 contributions0 · 16: No activity0 · 17: 2 contributions0 · 18: 1 contribution0 · 19: No activity0 · 20: No activity0 · 21: No activity0 · 22: 3 contributions0 · 23: No activity0 · 24: 3 contributions0 · 25: No activity0 · 26: No activity0 · 27: 4 contributions0 · 28: No activity0 · 29: No activity0 · 30: No activity0 · 31: No activity0 · 32: No activity0 · 33: No activity0 · 34: No activity0 · 35: 1 contribution0 · 36: 4 contributions0 · 37: 4 contributions0 · 38: No activity0 · 39: No activity0 · 40: 2 contributions0 · 41: 2 contributions0 · 42: 2 contributions0 · 43: No activity0 · 44: 3 contributions0 · 45: 2 contributions0 · 46: 1 contribution0 · 47: No activity0 · 48: No activity0 · 49: No activity0 · 50: 1 contribution0 · 51: 2 contributions0 · 52: 3 contributions1 · 0: 3 contributions1 · 1: No activity1 · 2: 4 contributions1 · 3: 2 contributions1 · 4: 2 contributions1 · 5: No activity1 · 6: No activity1 · 7: No activity1 · 8: No activity1 · 9: 2 contributions1 · 10: No activity1 · 11: No activity1 · 12: No activity1 · 13: No activity1 · 14: 2 contributions1 · 15: 2 contributions1 · 16: No activity1 · 17: No activity1 · 18: 1 contribution1 · 19: No activity1 · 20: No activity1 · 21: No activity1 · 22: 1 contribution1 · 23: 4 contributions1 · 24: No activity1 · 25: 1 contribution1 · 26: No activity1 · 27: 3 contributions1 · 28: 1 contribution1 · 29: No activity1 · 30: 1 contribution1 · 31: No activity1 · 32: No activity1 · 33: No activity1 · 34: No activity1 · 35: 1 contribution1 · 36: No activity1 · 37: No activity1 · 38: No activity1 · 39: No activity1 · 40: No activity1 · 41: 1 contribution1 · 42: 1 contribution1 · 43: No activity1 · 44: 2 contributions1 · 45: No activity1 · 46: No activity1 · 47: 1 contribution1 · 48: No activity1 · 49: No activity1 · 50: No activity1 · 51: No activity1 · 52: No activity2 · 0: No activity2 · 1: No activity2 · 2: No activity2 · 3: 3 contributions2 · 4: No activity2 · 5: No activity2 · 6: 1 contribution2 · 7: No activity2 · 8: 1 contribution2 · 9: No activity2 · 10: No activity2 · 11: No activity2 · 12: No activity2 · 13: No activity2 · 14: 1 contribution2 · 15: No activity2 · 16: 2 contributions2 · 17: No activity2 · 18: No activity2 · 19: 1 contribution2 · 20: 2 contributions2 · 21: 1 contribution2 · 22: 1 contribution2 · 23: No activity2 · 24: No activity2 · 25: No activity2 · 26: No activity2 · 27: 3 contributions2 · 28: No activity2 · 29: No activity2 · 30: 1 contribution2 · 31: 3 contributions2 · 32: No activity2 · 33: No activity2 · 34: 3 contributions2 · 35: No activity2 · 36: No activity2 · 37: 2 contributions2 · 38: 1 contribution2 · 39: 2 contributions2 · 40: No activity2 · 41: No activity2 · 42: No activity2 · 43: 1 contribution2 · 44: 3 contributions2 · 45: No activity2 · 46: No activity2 · 47: 1 contribution2 · 48: 1 contribution2 · 49: 1 contribution2 · 50: 3 contributions2 · 51: 3 contributions2 · 52: 1 contribution3 · 0: 4 contributions3 · 1: No activity3 · 2: No activity3 · 3: 2 contributions3 · 4: 2 contributions3 · 5: 2 contributions3 · 6: No activity3 · 7: 3 contributions3 · 8: 2 contributions3 · 9: 1 contribution3 · 10: No activity3 · 11: No activity3 · 12: No activity3 · 13: 1 contribution3 · 14: 2 contributions3 · 15: 3 contributions3 · 16: 1 contribution3 · 17: 2 contributions3 · 18: No activity3 · 19: 2 contributions3 · 20: No activity3 · 21: No activity3 · 22: No activity3 · 23: 3 contributions3 · 24: No activity3 · 25: No activity3 · 26: No activity3 · 27: No activity3 · 28: 2 contributions3 · 29: No activity3 · 30: 3 contributions3 · 31: 2 contributions3 · 32: No activity3 · 33: No activity3 · 34: 1 contribution3 · 35: 1 contribution3 · 36: No activity3 · 37: 1 contribution3 · 38: No activity3 · 39: 2 contributions3 · 40: No activity3 · 41: No activity3 · 42: 1 contribution3 · 43: No activity3 · 44: No activity3 · 45: No activity3 · 46: No activity3 · 47: 2 contributions3 · 48: No activity3 · 49: 1 contribution3 · 50: 2 contributions3 · 51: 1 contribution3 · 52: 2 contributions4 · 0: No activity4 · 1: No activity4 · 2: No activity4 · 3: No activity4 · 4: 1 contribution4 · 5: 1 contribution4 · 6: No activity4 · 7: 2 contributions4 · 8: No activity4 · 9: No activity4 · 10: 1 contribution4 · 11: No activity4 · 12: No activity4 · 13: No activity4 · 14: No activity4 · 15: No activity4 · 16: No activity4 · 17: No activity4 · 18: 2 contributions4 · 19: 1 contribution4 · 20: 1 contribution4 · 21: No activity4 · 22: 2 contributions4 · 23: No activity4 · 24: No activity4 · 25: 3 contributions4 · 26: No activity4 · 27: 1 contribution4 · 28: No activity4 · 29: 1 contribution4 · 30: 1 contribution4 · 31: 1 contribution4 · 32: No activity4 · 33: 2 contributions4 · 34: No activity4 · 35: 2 contributions4 · 36: No activity4 · 37: No activity4 · 38: No activity4 · 39: No activity4 · 40: No activity4 · 41: 1 contribution4 · 42: No activity4 · 43: 2 contributions4 · 44: 4 contributions4 · 45: No activity4 · 46: 4 contributions4 · 47: 2 contributions4 · 48: No activity4 · 49: No activity4 · 50: 1 contribution4 · 51: 3 contributions4 · 52: No activity5 · 0: 2 contributions5 · 1: 1 contribution5 · 2: 2 contributions5 · 3: No activity5 · 4: No activity5 · 5: No activity5 · 6: 1 contribution5 · 7: 3 contributions5 · 8: No activity5 · 9: No activity5 · 10: 1 contribution5 · 11: 1 contribution5 · 12: 1 contribution5 · 13: 3 contributions5 · 14: 3 contributions5 · 15: 1 contribution5 · 16: No activity5 · 17: No activity5 · 18: No activity5 · 19: 3 contributions5 · 20: 1 contribution5 · 21: No activity5 · 22: No activity5 · 23: No activity5 · 24: 1 contribution5 · 25: No activity5 · 26: No activity5 · 27: No activity5 · 28: 2 contributions5 · 29: 2 contributions5 · 30: 1 contribution5 · 31: No activity5 · 32: No activity5 · 33: No activity5 · 34: No activity5 · 35: No activity5 · 36: 3 contributions5 · 37: No activity5 · 38: 4 contributions5 · 39: 2 contributions5 · 40: 2 contributions5 · 41: No activity5 · 42: No activity5 · 43: No activity5 · 44: No activity5 · 45: 2 contributions5 · 46: No activity5 · 47: No activity5 · 48: No activity5 · 49: No activity5 · 50: 2 contributions5 · 51: 2 contributions5 · 52: No activity6 · 0: 1 contribution6 · 1: No activity6 · 2: 2 contributions6 · 3: No activity6 · 4: No activity6 · 5: 1 contribution6 · 6: No activity6 · 7: No activity6 · 8: No activity6 · 9: No activity6 · 10: 2 contributions6 · 11: No activity6 · 12: 1 contribution6 · 13: 2 contributions6 · 14: 1 contribution6 · 15: 2 contributions6 · 16: No activity6 · 17: 1 contribution6 · 18: 2 contributions6 · 19: 3 contributions6 · 20: 3 contributions6 · 21: 3 contributions6 · 22: No activity6 · 23: No activity6 · 24: 3 contributions6 · 25: No activity6 · 26: 1 contribution6 · 27: 1 contribution6 · 28: No activity6 · 29: 4 contributions6 · 30: 1 contribution6 · 31: No activity6 · 32: 1 contribution6 · 33: 3 contributions6 · 34: 1 contribution6 · 35: 1 contribution6 · 36: No activity6 · 37: No activity6 · 38: No activity6 · 39: 3 contributions6 · 40: No activity6 · 41: No activity6 · 42: 1 contribution6 · 43: No activity6 · 44: 1 contribution6 · 45: No activity6 · 46: No activity6 · 47: No activity6 · 48: No activity6 · 49: No activity6 · 50: 1 contribution6 · 51: No activity6 · 52: 2 contributionsLessMore
@vireya/ui/charts/heatmap/correlation

Symmetric correlation matrix with a diverging color scale (-1..1) and the HeatmapCellLabels primitive rendering values inside cells with auto-contrast text.

client
revenuesignupsactive_userschurnNPSsupport_ticketsrevenuesignupsactive_userschurnNPSsupport_ticketsrevenue · revenue: 1.00revenue · signups: 0.78revenue · active_users: 0.64revenue · churn: -0.42revenue · NPS: 0.31revenue · support_tickets: -0.18signups · revenue: 0.78signups · signups: 1.00signups · active_users: 0.71signups · churn: -0.35signups · NPS: 0.28signups · support_tickets: -0.22active_users · revenue: 0.64active_users · signups: 0.71active_users · active_users: 1.00active_users · churn: -0.51active_users · NPS: 0.44active_users · support_tickets: -0.29churn · revenue: -0.42churn · signups: -0.35churn · active_users: -0.51churn · churn: 1.00churn · NPS: -0.66churn · support_tickets: 0.58NPS · revenue: 0.31NPS · signups: 0.28NPS · active_users: 0.44NPS · churn: -0.66NPS · NPS: 1.00NPS · support_tickets: -0.39support_tickets · revenue: -0.18support_tickets · signups: -0.22support_tickets · active_users: -0.29support_tickets · churn: 0.58support_tickets · NPS: -0.39support_tickets · support_tickets: 1.001.000.780.64-0.420.31-0.180.781.000.71-0.350.28-0.220.640.711.00-0.510.44-0.29-0.42-0.35-0.511.00-0.660.580.310.280.44-0.661.00-0.39-0.18-0.22-0.290.58-0.391.00

Understanding Heatmap charts

A heatmap maps values onto a 2D grid and encodes each cell with colour intensity, letting you spot patterns, clusters and outliers across two dimensions at once — activity by day-of-week and hour, or correlations across many variables.

recharts has no native heatmap, so Vireya composes one from SVG primitives inside its ChartContainer, deriving cell colour from your accent token via color-mix with native title tooltips.

When to use

  • Activity or density across two categorical axes (calendar heatmaps, cohort grids).
  • Correlation matrices across many numeric variables.
  • Spotting hotspots and gaps in a large but structured dataset.

When to avoid

  • Precise value reading — colour encodes magnitude only approximately.
  • Few data points, where a bar or table is clearer.
  • Sequential trends better served by a line chart.

Best practices

  • Choose a sequential scale for magnitude and a diverging scale for signed data like correlation.
  • Print values inside cells when precision matters and space allows.
  • Keep the scale perceptually uniform so equal steps look equal.
  • Give cells a subtle gap or border so the grid structure reads.

Accessibility

  • Provide a legend mapping colour to value range.
  • Use auto-contrast text labels inside cells where exact values matter.
  • Offer the data as a table for users who can't perceive the colour encoding.

Frequently asked questions

Why doesn't recharts have a heatmap out of the box?
recharts focuses on cartesian and polar series. A heatmap is a grid of coloured cells rather than a series, so Vireya builds it from SVG primitives inside the same ChartContainer, keeping tokens and tooltips consistent with the rest of the library.
What colour scale should a heatmap use?
Use a sequential scale (light to dark in one hue) for magnitude, and a diverging scale (two hues meeting at a neutral midpoint) for signed data such as a -1..1 correlation matrix.
Can I show the exact numbers in a heatmap?
Yes. Vireya's correlation variant renders values inside each cell with automatically contrasting text, so the grid reads both as a pattern and as exact figures.