A high-performance, GitHub-like contribution heatmap widget for Flutter. This widget provides a visual representation of contribution data over time, similar to GitHub's contribution graph with proper i18n support and intelligent month separation.
- π Ultra-High Performance: Custom RenderBox implementation with optimized rendering pipeline
- π Interactive: Full tap support with proper hit testing and gesture handling
- π¨ Fully Customizable: Colors, sizing, labels, and layout options
- π Split Month View: Visual month separation with intelligent empty cell insertion
- π Cell Date Display: NEW! Show day numbers inside contribution cells
- βΏ Accessibility Ready: Supports text scaling and high contrast modes
- π Internationalized: Locale-aware text rendering with customizable start weekdays
- πΎ Memory Efficient: Optimized data structures minimize memory usage and GC pressure
- π§ Smart Invalidation: Only recomputes what's needed, not on every frame
Visit our Visual Playground Website, play with ContributionHeatmap, copy the generated code, and seamlessly integrate it into your project. This is the quickest way! π₯°
import 'package:flutter/material.dart';
import 'package:contribution_heatmap/contribution_heatmap.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ContributionHeatmap(
entries: [
ContributionEntry(DateTime(2025, 11, 15), 5),
ContributionEntry(DateTime(2025, 11, 16), 3),
ContributionEntry(DateTime(2025, 11, 17), 8),
// Add more entries...
],
onCellTap: (date, value) {
print('Tapped: $date with $value contributions');
},
);
}
}The data structure for contribution data:
class ContributionEntry {
final DateTime date; // Day-level precision
final int count; // Number of contributions (>= 0)
const ContributionEntry(this.date, this.count);
}Currently, this package supports English (EN) and:
- π«π· French (fr-FR)
- π©πͺ German (de-DE)
- πͺπΈ Spanish (es-ES)
More languages will be added soon.
Exemple de Contribution Heatmap en franΓ§ais (fr-FR)

| Property | Type | Default | Description |
|---|---|---|---|
cellSize |
double |
12.0 |
Size of each contribution cell |
cellSpacing |
double |
3.0 |
Spacing between cells |
cellRadius |
double |
2.0 |
Corner radius for rounded cells |
padding |
EdgeInsets |
EdgeInsets.all(16) |
Outer padding around widget |
| Property | Type | Default | Description |
|---|---|---|---|
showMonthLabels |
bool |
true |
Show month names above the heatmap |
weekdayLabel |
WeekdayLabel |
WeekdayLabel.full |
Determines which weekday labels to display to the left of the heatmap (REPLACES showWeekdayLabels) |
showCellDate |
bool |
false |
Show date numbers inside cells |
cellDateTextStyle |
TextStyle? |
null |
Custom style for cell date numbers |
monthTextStyle |
TextStyle? |
null |
Custom style for month labels |
weekdayTextStyle |
TextStyle? |
null |
Custom style for weekday labels |
| Property | Type | Default | Description |
|---|---|---|---|
minDate |
DateTime? |
null |
Override minimum date (auto-calculated if null) |
maxDate |
DateTime? |
null |
Override maximum date (auto-calculated if null) |
startWeekday |
int |
DateTime.monday |
First day of week (1=Mon, 7=Sun) |
splittedMonthView |
bool |
false |
Enable visual month separation |
| Property | Type | Default | Description |
|---|---|---|---|
heatmapColor |
HeatmapColor |
green |
Available color schemes for the contribution heatmap. |
onCellTap |
void Function(DateTime, int)? |
null |
Callback for cell tap events |
- O(1) cell value lookups during painting
- Custom RenderBox implementation bypasses widget rebuilds
- Smart invalidation - only recomputes when properties actually change
- Efficient hit testing with proper bounds checking
- Optimized split month rendering with minimal computational overhead
- Intelligent cell date rendering with automatic size detection
- HashMap-based data structure for fast lookups
- Minimal object allocation during painting
- Proper gesture recognizer cleanup prevents memory leaks
- Optimized text rendering with cached TextPainter objects
- Linear date sequence for efficient split month calculations
- Handles thousands of data points efficiently
- Constant time complexity for cell rendering
- Responsive layout adapts to available space
- Smooth interactions even with large datasets and split months
If you are upgrading from a version older than 0.5.0 that used the boolean showWeekdayLabels, apply the following replacements:
| Property | Before | After |
|---|---|---|
| Weekday labels β hidden | showWeekdayLabels: false |
weekdayLabel: WeekdayLabel.none |
| Weekday labels β shown (all days) | showWeekdayLabels: true |
weekdayLabel: WeekdayLabel.full |
| GitHub-style labels (Mon, Wed, Fri) | weekdayLabel: WeekdayLabel.githubLike |
Feel free to contribute! Check out the guides for more information.
Here are a few ways you can show support:
- βοΈ Star it on GitHub β stars help others discover it!
- π Give it a thumbs up on pub.dev β every bit of appreciation counts!
- π Try my TypeFast app, a fun way to sharpen your touch typing skills with games.
- π Explore more of my work!

