GitHub-style activity heatmap for React Native. SVG cells with multiple visualization modes, touch tooltips, animations, and a flexible color scale API.
npm install @rific/heatmapnpm install react-native-svgFollow the react-native-svg installation guide to link the native module.
import Heatmap from '@rific/heatmap'
const data = [
{ date: '2026-01-15', value: 3 },
{ date: '2026-03-08', value: 14 },
{ date: '2026-05-01', value: 7 },
]
export default function App() {
return (
<Heatmap.Calendar
data={data}
onDayPress={(point, date) => console.log(date, point)}
/>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
data |
DataPoint[] |
required | Array of { date, value } objects. date is YYYY-MM-DD. |
startDate |
Date |
1 year ago | First day shown on the grid. |
endDate |
Date |
Today | Last day shown on the grid. |
cellMode |
'solid' | 'gradient' | 'density' | 'stacked' | 'dots' | 'priority' |
'solid' |
Visual style of each cell. |
colorScale |
Partial<ColorScale> |
GitHub greens | Thresholds and colors used to shade cells. |
color |
string |
— | Single accent color. Overrides the default color scale. |
colorScheme |
'light' | 'dark' |
— | Switch between built-in light and dark palettes. |
autoScale |
boolean |
true |
Scale cell intensity relative to the max value in data. |
theme |
Partial<HeatmapTheme> |
See below | Size, spacing, and color overrides. |
showMonthLabels |
boolean |
true |
Show month name labels above the grid. |
showDayLabels |
boolean |
true |
Show Mon / Wed / Fri labels on the left. |
animated |
boolean |
false |
Enable all animations (load ripple, today pulse, press spring). |
scrollToToday |
boolean |
true |
Scroll to the current week on mount. |
scrollEnabled |
boolean |
true |
Enable or disable horizontal scrolling. |
onDayPress |
(point: DataPoint | null, date: string) => void |
— | Called when a cell is tapped. |
onEndReached |
() => void |
— | Called when the user scrolls near the right edge. Use for infinite scroll. |
onEndReachedThreshold |
number |
0.1 |
Fraction of total width from the right edge that triggers onEndReached. |
renderTooltip |
(data: TooltipData) => ReactNode |
— | Replace the default tooltip with a custom component. |
renderCell |
(data: DataPoint | null, date: string) => ReactNode |
— | Replace the default cell with a custom component. |
tooltipLabel |
string |
'event' |
Unit label in the default tooltip. Pluralized automatically (e.g. 'workout' → '3 workouts'). |
tooltipEmptyLabel |
string |
'No events' |
Label shown in the tooltip for days with no data. |
Each cell is a flat colored rectangle, identical to the GitHub contribution graph.
A radial gradient blooms from the center of each cell — dim at the center, full color at the edges.
A circle grows inside a neutral background rectangle. A small dot means low activity; a filled square means high activity.
Horizontal slices represent proportional segments from the segments array on each DataPoint.
Each segment in the segments array is drawn as a dot sized by its relative weight.
The dominant segment's color fills the cell at an opacity proportional to its value.
<Heatmap.Calendar data={data} cellMode='density' />Pass animated to enable all animations. No extra dependencies — uses the built-in Animated API.
<Heatmap.Calendar data={data} animated />- Load ripple — cells fade and scale in on mount, radiating outward from today's column.
- Today pulse — the current day cell breathes with a looping scale animation.
- Press spring — cells scale down on press and spring back on release.
The current day always receives a border indicator regardless of the animated prop.
<Heatmap.Calendar
data={data}
startDate={startDate}
endDate={endDate}
onEndReached={() => setEndDate(extendedDate)}
onEndReachedThreshold={0.15}
/>When the user scrolls within onEndReachedThreshold of the right edge, onEndReached fires. Update endDate to append more weeks.
For multi-category data, pass a segments array on each DataPoint. Works with stacked, dots, and priority cell modes.
const data = [
{
date: '2026-05-01',
value: 10,
segments: [
{ color: '#40c463', value: 6 },
{ color: '#216e39', value: 4 },
],
},
]
<Heatmap.Calendar data={data} cellMode='stacked' /><Heatmap.Calendar
data={data}
colorScale={{
thresholds: [1, 4, 8, 16], // 4 thresholds → 5 colors
colors: ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'],
emptyColor: '#ebedf0',
}}
/>Values below the first threshold use colors[0]. Values at or above threshold n use colors[n + 1]. Values above the last threshold use the last color.
<Heatmap.Calendar
data={data}
theme={{
cellSize: 14,
cellRadius: 2,
gutterSize: 2,
monthLabelColor: '#57606a',
dayLabelColor: '#57606a',
backgroundColor: 'transparent',
tooltipBackgroundColor: '#1b1f23',
tooltipTextColor: '#ffffff',
todayColor: '#4183c4',
todayBorderColor: '#4183c4',
}}
/><Heatmap.Calendar
data={data}
renderTooltip={({ date, value }) => (
<View style={styles.tooltip}>
<Text>{date} — {value} events</Text>
</View>
)}
/><Heatmap.Calendar
data={data}
renderCell={(point, date) => (
<View style={{ width: 14, height: 14, backgroundColor: point ? 'tomato' : '#eee', borderRadius: 2 }} />
)}
/>All types are exported:
import Heatmap, { type CellMode, type ColorScale, type DataPoint, type HeatmapProps, type HeatmapTheme, type TooltipData } from '@rific/heatmap'npm run typecheck # TypeScript
npm run lint # ESLint
npm run fix # ESLint --fix
npm test # Jest
npm run test:watch # Jest watch modeMIT © Jay Deaton