
Security News
Risky Biz Podcast: Making Reachability Analysis Work in Real-World Codebases
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
@dt-workspace/react-native-heatmap
Advanced tools
A modern, highly customizable React Native heatmap component library inspired by GitHub's contribution calendar
A modern, highly customizable React Native heatmap component library inspired by GitHub's contribution calendar. Perfect for visualizing activity data, progress tracking, and creating beautiful data representations in your React Native applications.
GitHub-style contribution calendar with advanced animations, gestures, and tooltips
# Using npm
npm install @dt-workspace/react-native-heatmap react-native-svg
# Using yarn
yarn add @dt-workspace/react-native-heatmap react-native-svg
# Using pnpm
pnpm add @dt-workspace/react-native-heatmap react-native-svg
For advanced animations and gestures, install these optional peer dependencies:
# For animations (optional)
npm install react-native-reanimated
# For gestures (optional)
npm install react-native-gesture-handler
# Or with yarn
yarn add react-native-reanimated react-native-gesture-handler
iOS: cd ios && pod install
Android: No additional setup required
Expo: Compatible with Expo SDK 48+
import React from 'react';
import { View } from 'react-native';
import { Heatmap } from '@dt-workspace/react-native-heatmap';
import type { HeatmapData } from '@dt-workspace/react-native-heatmap';
const data: HeatmapData[] = [
{ date: '2024-01-01', value: 3 },
{ date: '2024-01-02', value: 7 },
{ date: '2024-01-03', value: 1 },
// ... more data
];
const App = () => {
const startDate = new Date('2024-01-01');
return (
<View style={{ padding: 20 }}>
<Heatmap
data={data}
startDate={startDate}
colorScheme="github"
onCellPress={(data, index) => {
console.log('Pressed:', data);
}}
/>
</View>
);
};
export default App;
Create smooth, eye-catching animations for your heatmaps:
<Heatmap
data={data}
animated={true}
animation={{
enabled: true,
duration: 300,
entryAnimation: 'scale', // 'fade', 'scale', 'slide'
staggerDelay: 10,
useNativeDriver: true,
}}
/>
Rich interaction support with haptic feedback:
<Heatmap
data={data}
// Basic touches
onCellPress={(data, index) => console.log('Tap:', data)}
onCellLongPress={(data, index) => console.log('Long press:', data)}
onCellDoublePress={(data, index) => console.log('Double tap:', data)}
onCellPressIn={(data, index) => console.log('Press in:', data)}
onCellPressOut={(data, index) => console.log('Press out:', data)}
// Haptic feedback
hapticFeedback={true}
// Gesture support (requires react-native-gesture-handler)
gesture={{
enabled: true,
pan: true,
zoom: true,
minZoom: 0.5,
maxZoom: 3.0,
}}
/>
Beautiful, configurable tooltips with smart positioning:
<Heatmap
data={data}
tooltip={{
enabled: true,
position: 'auto', // 'top', 'bottom', 'left', 'right', 'auto'
showArrow: true,
backgroundColor: '#333',
textColor: '#fff',
content: (data) => (
<View>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
{data.date}
</Text>
<Text style={{ color: 'white' }}>
Value: {data.value}
</Text>
</View>
),
}}
/>
Choose from expanded color schemes including new v1.1.0 additions:
// GitHub style (default)
<Heatmap data={data} colorScheme="github" />
// New in v1.1.0
<Heatmap data={data} colorScheme="gitlab" />
<Heatmap data={data} colorScheme="bitbucket" />
<Heatmap data={data} colorScheme="accessible" />
<Heatmap data={data} colorScheme="sunset" />
<Heatmap data={data} colorScheme="neon" />
// Classic schemes
<Heatmap data={data} colorScheme="heat" />
<Heatmap data={data} colorScheme="cool" />
// Custom color scheme
<Heatmap
data={data}
colorScheme={{
name: 'custom',
colors: ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'],
emptyColor: '#ebedf0'
}}
/>
Available schemes: github
, githubDark
, gitlab
, bitbucket
, accessible
, sunset
, neon
, heat
, cool
, purple
, green
, orange
, red
, blue
, grayscale
Perfect for contribution calendars and date-based visualizations:
<Heatmap
data={data}
layout="calendar"
showMonthLabels={true}
showWeekdayLabels={true}
startDate={new Date('2024-01-01')}
endDate={new Date('2024-12-31')}
/>
Ideal for non-date based data:
<Heatmap
data={data}
layout="grid"
columns={7}
rows={5}
/>
Single row visualization:
<Heatmap
data={data}
layout="compact"
/>
Customize the appearance of your heatmap cells:
// Square cells (default)
<Heatmap data={data} cellShape="square" />
// Rounded corners
<Heatmap data={data} cellShape="rounded" />
// Circular cells
<Heatmap data={data} cellShape="circle" />
Handle large datasets efficiently with virtualization:
<Heatmap
data={largeDataset} // 1000+ items
virtualized={true}
renderBuffer={50}
// Performance monitoring
onPerformanceUpdate={(metrics) => {
console.log('Render time:', metrics.renderTime);
}}
/>
Create consistent themes across light and dark modes:
<Heatmap
data={data}
theme={{
colors: {
background: '#0d1117',
text: '#f0f6fc',
border: '#30363d',
tooltip: '#f0f6fc',
tooltipText: '#0d1117',
},
spacing: {
cell: 3,
margin: 15,
padding: 10,
},
typography: {
fontSize: 14,
fontWeight: 'bold',
fontFamily: 'System',
},
}}
/>
<Heatmap
data={data}
cellSize={15}
cellSpacing={3}
width={350}
height={200}
/>
<Heatmap
data={data}
accessibility={{
label: "Activity heatmap",
hint: "Double tap to view details",
role: "grid",
}}
/>
import { Heatmap } from '@dt-workspace/react-native-heatmap';
const GitHubContributions = ({ contributionData }) => {
const startDate = new Date();
startDate.setDate(startDate.getDate() - 365);
return (
<Heatmap
data={contributionData}
startDate={startDate}
colorScheme="github"
layout="calendar"
showMonthLabels={true}
showWeekdayLabels={true}
// v1.1.0 features
animated={true}
animation={{
entryAnimation: 'scale',
staggerDelay: 5,
duration: 200,
}}
tooltip={{
enabled: true,
content: (data) => (
<View>
<Text style={{ color: 'white', fontWeight: 'bold' }}>
{data.date}
</Text>
<Text style={{ color: 'white' }}>
{data.value} contributions
</Text>
<Text style={{ color: 'white', fontSize: 12 }}>
{data.metadata?.commits || 0} commits
</Text>
</View>
),
}}
onCellPress={(data) => showContributionDetails(data)}
onCellLongPress={(data) => showQuickActions(data)}
hapticFeedback={true}
/>
);
};
const FitnessHeatmap = ({ workoutData }) => (
<Heatmap
data={workoutData}
colorScheme="sunset"
cellShape="circle"
// Smooth animations
animated={true}
animation={{
entryAnimation: 'fade',
duration: 400,
staggerDelay: 8,
}}
// Interactive features
onCellPress={(data) => {
navigation.navigate('WorkoutDetails', { date: data.date });
}}
onCellDoublePress={(data) => {
quickAddWorkout(data.date);
}}
hapticFeedback={true}
theme={{
colors: {
background: '#f8f9fa',
text: '#495057',
}
}}
/>
);
The library now supports 7 different time-based layout types for various data visualization needs:
Perfect for showing hourly activity patterns throughout a day.
import { Heatmap } from '@dt-workspace/react-native-heatmap';
const DailyActivity = ({ hourlyData }) => (
<Heatmap
data={hourlyData}
layout="daily"
targetDate={new Date('2024-01-15')}
hourFormat="24h"
showTimeLabels={true}
colorScheme="heat"
cellSize={20}
cellSpacing={3}
onCellPress={(data) => {
console.log('Hour:', data.date, 'Activity:', data.value);
}}
/>
);
Ideal for weekly activity tracking and habit visualization.
const WeeklyTracker = ({ weeklyData }) => (
<Heatmap
data={weeklyData}
layout="weekly"
targetDate={new Date('2024-01-15')}
showTimeLabels={true}
colorScheme="github"
cellSize={30}
cellSpacing={4}
/>
);
Perfect for monthly overviews and calendar-style visualizations.
const MonthlyOverview = ({ monthlyData }) => (
<Heatmap
data={monthlyData}
layout="monthly"
targetDate={new Date('2024-01-01')}
showTimeLabels={true}
colorScheme="cool"
cellSize={15}
cellSpacing={2}
/>
);
Great for showing annual patterns and long-term trends.
const YearlyReport = ({ yearlyData }) => (
<Heatmap
data={yearlyData}
layout="yearly"
targetDate={new Date('2024-01-01')}
showTimeLabels={true}
colorScheme="purple"
cellSize={8}
cellSpacing={1}
/>
);
Flexible layout for custom date ranges with configurable granularity.
const CustomRangeView = ({ rangeData }) => (
<Heatmap
data={rangeData}
layout="customRange"
customRange={{
start: new Date('2024-01-01'),
end: new Date('2024-03-31'),
granularity: 'week' // 'hour' | 'day' | 'week' | 'month'
}}
showTimeLabels={true}
colorScheme="green"
cellSize={25}
cellSpacing={3}
/>
);
Horizontal scrollable timeline for large datasets.
const TimelineView = ({ timelineData }) => (
<Heatmap
data={timelineData}
layout="timelineScroll"
scrollDirection="horizontal"
showTimeLabels={true}
colorScheme="blue"
cellSize={12}
cellSpacing={2}
/>
);
Live updating layout for real-time data visualization.
const RealTimeMonitor = ({ liveData }) => (
<Heatmap
data={liveData}
layout="realTime"
updateInterval={1000}
showTimeLabels={true}
colorScheme="neon"
cellSize={15}
cellSpacing={2}
animated={true}
/>
);
A flexible card-based layout system for composing complex UI components with configurable sections.
import { CardLayout } from '@dt-workspace/react-native-heatmap';
const BasicCard = () => (
<CardLayout
title="Analytics Dashboard"
description="Monthly performance overview"
customComponent={
<Heatmap
data={analyticsData}
layout="monthly"
colorScheme="github"
cellSize={12}
/>
}
hitman={
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Button title="View Details" />
<Button title="Export" />
</View>
}
/>
);
const AdvancedCard = () => (
<CardLayout
title="Project Activity"
description="Team collaboration metrics"
// Badges for status indicators
badgesArray={[
{ text: 'Active', backgroundColor: '#28a745', color: '#fff' },
{ text: 'High Priority', backgroundColor: '#dc3545', color: '#fff' },
{ text: 'Team: 5', backgroundColor: '#6c757d', color: '#fff' }
]}
// Custom content area
customComponent={
<View>
<Heatmap
data={projectData}
layout="weekly"
colorScheme="gitlab"
cellSize={15}
cellSpacing={2}
/>
<Text style={{ textAlign: 'center', marginTop: 10 }}>
Last 7 days activity
</Text>
</View>
}
// Footer actions
hitman={
<View style={{ flexDirection: 'row' }}>
<Button title="Settings" />
<Button title="Share" />
</View>
}
// Configuration
cardLayout={{
borderRadius: 12,
shadow: true,
backgroundColor: '#f8f9fa'
}}
// Theme
theme="light"
// Animations
animated={true}
animationType="fade"
animationDuration={300}
// Interactions
onPress={() => console.log('Card pressed')}
onLongPress={() => console.log('Card long pressed')}
/>
);
const CustomSectionCard = () => (
<CardLayout
title="Custom Layout"
titleSection={{ order: 0, visible: true, padding: 16 }}
description="Sections can be reordered and configured"
descriptionSection={{ order: 2, visible: true, padding: 12 }}
customComponent={<MyCustomComponent />}
customComponentSection={{ order: 1, visible: true, padding: 8 }}
hitman={<MyFooterComponent />}
hitmanSection={{ order: 3, visible: true, padding: 16 }}
// Individual section styling
titleStyle={{ fontSize: 18, fontWeight: 'bold' }}
descriptionStyle={{ fontSize: 14, color: '#666' }}
titleContainerStyle={{ backgroundColor: '#f0f0f0' }}
/>
);
Prop | Type | Default | Description |
---|---|---|---|
data | HeatmapData[] | Required | Array of data points with date and value |
startDate | Date | Current year start | Start date for the heatmap |
endDate | Date | Current year end | End date for the heatmap |
colorScheme | string | ColorScheme | 'github' | Color scheme name or custom scheme |
layout | LayoutType | 'calendar' | Layout type ('calendar' | 'grid' | 'compact' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'customRange' | 'timelineScroll' | 'realTime' ) |
cellSize | number | 12 | Size of each cell in pixels |
cellSpacing | number | 2 | Spacing between cells |
cellShape | 'square' | 'rounded' | 'circle' | 'square' | Shape of cells |
onCellPress | (data, index) => void | undefined | Cell press handler |
onCellLongPress | (data, index) => void | undefined | Cell long press handler |
New in v1.1.0 | |||
onCellDoublePress | (data, index) => void | undefined | Cell double press handler |
onCellPressIn | (data, index) => void | undefined | Cell press in handler |
onCellPressOut | (data, index) => void | undefined | Cell press out handler |
animated | boolean | true | Enable animations |
animation | AnimationConfig | undefined | Animation configuration |
tooltip | TooltipConfig | undefined | Tooltip configuration |
gesture | GestureConfig | undefined | Gesture configuration |
hapticFeedback | boolean | false | Enable haptic feedback |
virtualized | boolean | false | Enable virtualization for large datasets |
theme | Partial<Theme> | DEFAULT_THEME | Theme configuration |
showMonthLabels | boolean | true | Show month labels (calendar layout) |
showWeekdayLabels | boolean | true | Show weekday labels (calendar layout) |
New in v1.2.0 | |||
targetDate | Date | undefined | Target date for time-based layouts |
hourFormat | '12h' | '24h' | '24h' | Hour format for daily layouts |
showTimeLabels | boolean | false | Show time labels for time-based layouts |
scrollDirection | 'horizontal' | 'vertical' | 'horizontal' | Scroll direction for timeline layouts |
updateInterval | number | 1000 | Update interval for real-time layouts (ms) |
customRange | CustomRangeConfig | undefined | Custom range configuration |
Prop | Type | Default | Description |
---|---|---|---|
title | string | ReactNode | undefined | Card title (string or custom component) |
description | string | ReactNode | undefined | Card description (string or custom component) |
badges | ReactNode | undefined | Custom badges component |
badgesArray | BadgeConfig[] | undefined | Array of badge configurations |
customComponent | ReactNode | undefined | Custom content component |
hitman | ReactNode | undefined | Footer/action component (always rendered last) |
cardLayout | CardLayoutConfig | DEFAULT_CARD_LAYOUT | Card layout configuration |
theme | 'light' | 'dark' | 'auto' | 'light' | Theme mode |
themeColors | ThemeColors | undefined | Custom theme colors |
animated | boolean | false | Enable animations |
animationType | 'fade' | 'scale' | 'slide' | 'fade' | Animation type |
animationDuration | number | 300 | Animation duration (ms) |
onPress | () => void | undefined | Card press handler |
onLongPress | () => void | undefined | Card long press handler |
accessibilityLabel | string | undefined | Accessibility label |
accessibilityRole | string | undefined | Accessibility role |
testID | string | undefined | Test identifier |
interface HeatmapData {
date: string; // ISO date string (YYYY-MM-DD)
value: number;
metadata?: Record<string, any>;
}
interface AnimationConfig {
enabled: boolean;
duration: number;
easing?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out';
staggerDelay?: number;
entryAnimation?: 'fade' | 'scale' | 'slide' | 'none';
useNativeDriver?: boolean;
}
interface TooltipConfig {
enabled: boolean;
content?: (data: HeatmapData) => ReactNode;
position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
offset?: number;
showArrow?: boolean;
backgroundColor?: string;
textColor?: string;
fontSize?: number;
padding?: number;
borderRadius?: number;
shadow?: boolean;
}
interface GestureConfig {
enabled: boolean;
pan?: boolean;
zoom?: boolean;
swipe?: boolean;
minZoom?: number;
maxZoom?: number;
hapticFeedback?: boolean;
}
interface ColorScheme {
name: string;
colors: string[];
levels?: number;
emptyColor?: string;
}
interface Theme {
colors: {
background: string;
text: string;
border: string;
tooltip: string;
tooltipText: string;
};
spacing: {
cell: number;
margin: number;
padding: number;
};
typography: {
fontSize: number;
fontWeight: string;
fontFamily: string;
};
}
// Time-based layout types (v1.2.0)
type LayoutType =
| 'calendar'
| 'grid'
| 'compact'
| 'daily'
| 'weekly'
| 'monthly'
| 'yearly'
| 'customRange'
| 'timelineScroll'
| 'realTime';
interface CustomRangeConfig {
start: Date;
end: Date;
granularity: 'hour' | 'day' | 'week' | 'month';
}
// CardLayout types (v1.2.0)
interface BadgeConfig {
text: string;
color?: string;
backgroundColor?: string;
size?: 'small' | 'medium' | 'large';
style?: ViewStyle;
textStyle?: TextStyle;
}
interface CardLayoutConfig {
width?: number;
height?: number;
backgroundColor?: string;
borderColor?: string;
borderWidth?: number;
borderRadius?: number;
shadow?: boolean;
elevation?: number;
padding?: number;
margin?: number;
style?: ViewStyle;
}
interface CardSectionConfig {
visible?: boolean;
order?: number;
style?: ViewStyle;
padding?: number;
margin?: number;
}
The library includes helpful utility functions:
import {
generateDateRange,
formatDateISO,
processHeatmapData,
COLOR_SCHEMES,
DEFAULT_THEME,
DARK_THEME
} from '@dt-workspace/react-native-heatmap';
// Generate date range
const dates = generateDateRange(
new Date('2024-01-01'),
new Date('2024-12-31')
);
// Access predefined schemes
console.log(COLOR_SCHEMES.github);
console.log(COLOR_SCHEMES.gitlab); // New in v1.1.0
v1.1.0 is fully backward compatible. To use new features:
// Before (v0.1.0) - still works
<Heatmap
data={data}
colorScheme="github"
onCellPress={handlePress}
/>
// After (v1.1.0) - enhanced with new features
<Heatmap
data={data}
colorScheme="github"
onCellPress={handlePress}
// New features
animated={true}
animation={{ entryAnimation: 'scale', staggerDelay: 10 }}
tooltip={{ enabled: true, position: 'auto' }}
onCellDoublePress={handleDoublePress}
hapticFeedback={true}
/>
# Run tests
yarn test
# Run tests with coverage
yarn test --coverage
# Run type checking
yarn typecheck
# Run linting
yarn lint
Run the example app to see all features in action:
# Install dependencies
yarn
# Run on iOS
yarn example ios
# Run on Android
yarn example android
# Run on Web
yarn example web
We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/dt-workspace/react-native-heatmap.git
# Install dependencies
yarn
# Start the example app
yarn example ios
See version.md for a detailed history of changes.
MIT Β© Deepak Tiwari
If this library helps you, please consider:
Built with β€οΈ using TypeScript and React Native
FAQs
A modern, highly customizable React Native heatmap component library inspired by GitHub's contribution calendar
We found that @dt-workspace/react-native-heatmap demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socketβs AI scanner detected the supply chain attack and flagged the malware.
Security News
CISAβs 2025 draft SBOM guidance adds new fields like hashes, licenses, and tool metadata to make software inventories more actionable.