GitHub-style contribution heatmaps are a hallmark of developer portfolios. Yet on mobile viewports, almost every implementation forces clumsy horizontal scrolling or clips the rightmost weeks. Here is how we engineered an adaptive, zero-scroll solution that scales dynamically across all viewport sizes.
The Root Problem with Fixed Cell Dimensions
A standard year-long heatmap contains 52 weeks of 7 days each—totaling 364 cells. When developers assign static dimensions like w-[10px] with gap-[3px], the minimum required width becomes:
52 columns × 10px + 51 gaps × 3px = 673pxOn a standard 375px mobile device, a 673px container forces either aggressive horizontal scrolling or awkward layout breakage. Hiding the scrollbar with CSS ([scrollbar-width:none]) only masks the issue—users are still forced to swipe horizontally to see their recent contributions.
The Solution: Flex-1 Columns with Fixed Heights
The key design insight is that while the horizontal width of columns can flex proportionally, the vertical height of each cell must remain fixed to preserve typographic balance.
By setting each week column to flex-1 within a full-width flex container, each column dynamically adapts to available space:
- Desktop (704px available): ~10.6px per column (nearly square)
- Tablet (550px available): ~8.2px per column
- Mobile (327px available): ~5.3px per column
<div className="flex gap-[1.5px] sm:gap-[3px] w-full">
{weeks.map((week, wIdx) => (
<div key={wIdx} className="flex flex-1 flex-col gap-[2px] sm:gap-[3px]">
{week.map((day, dIdx) => (
<div
key={dIdx}
className="w-full h-[10px] sm:h-[11px] rounded-[1px] sm:rounded-[2px]"
/>
))}
</div>
))}
</div>Key Takeaway: Maintaining
h-[10px] sm:h-[11px]ensures the 7-row height never shifts during responsive resizing, keeping the grid proportions elegant.
Anchoring Month Labels by Week Index
Most implementations use justify-between across the 12 month labels, resulting in equal spacing that drifts out of sync with actual calendar month boundaries.
Instead, we calculate the exact starting week index for each month and use percentage-based absolute positioning:
<span
className="absolute"
style={{ left: `${(m.weekIndex / 52) * 100}%` }}
>
{m.name}
</span>This guarantees month labels stay perfectly aligned with their respective columns regardless of container width.
Conclusion
By moving away from hardcoded pixel widths and embracing fractional flex scaling, the contribution heatmap becomes an integral, responsive component that looks intentional on every device.
