@rsalianto/git-heatmap-vanilla
v0.1.7
Published
Web Component (<git-heatmap>) for GitHub/GitLab contribution heatmaps — no framework required, CDN or npm
Maintainers
Readme
@rsalianto/git-heatmap-vanilla
Web Component (<git-heatmap>) for displaying GitHub/GitLab contribution heatmaps. No framework required.

Part of the
@rsalianto/git-heatmapfamily — available for React, Vue, Angular, Vanilla JS, and Next.js.
Installation
npm install @rsalianto/git-heatmap-vanilla@rsalianto/git-heatmap-core is not required as a separate install — buildHeatmapData, buildHeatmapDataForYear, and normalizeManual are re-exported directly from this package.
CDN usage (no build tool)
Option A — IIFE (recommended for plain HTML, no type="module" needed)
<script src="https://cdn.jsdelivr.net/npm/@rsalianto/git-heatmap-vanilla/dist/index.iife.js"></script>
<git-heatmap id="hm"></git-heatmap>
<script>
const { buildHeatmapData } = GitHeatmapVanilla;
document.getElementById("hm").data = buildHeatmapData([
{ date: "2025-06-01", count: 5 },
{ date: "2025-06-15", count: 12 },
]);
</script>Option B — ES module with import map
<script type="importmap">
{
"imports": {
"@rsalianto/git-heatmap-vanilla": "https://cdn.jsdelivr.net/npm/@rsalianto/git-heatmap-vanilla/dist/index.mjs",
"@rsalianto/git-heatmap-core": "https://cdn.jsdelivr.net/npm/@rsalianto/git-heatmap-core/dist/index.mjs"
}
}
</script>
<script type="module">
import { buildHeatmapData } from "@rsalianto/git-heatmap-vanilla";
import "@rsalianto/git-heatmap-vanilla";
document.querySelector("git-heatmap").data = buildHeatmapData([
{ date: "2025-06-01", count: 5 },
]);
</script>
<git-heatmap></git-heatmap>npm usage (with a bundler)
import "@rsalianto/git-heatmap-vanilla";
import { buildHeatmapData } from "@rsalianto/git-heatmap-vanilla";Usage
Fetch from an API endpoint
<git-heatmap api-url="/api/contributions"></git-heatmap>The endpoint must return a HeatmapData JSON object.
Pass data via JavaScript
import "@rsalianto/git-heatmap-vanilla";
import { buildHeatmapData } from "@rsalianto/git-heatmap-vanilla";
const el = document.querySelector("git-heatmap");
el.data = buildHeatmapData([
{ date: "2025-06-01", count: 5 },
{ date: "2025-06-02", count: 0 },
]);Display a specific year
import { buildHeatmapDataForYear } from "@rsalianto/git-heatmap-vanilla";
el.data = buildHeatmapDataForYear(allEntries, 2024);Custom fetch function
el.fetchData = () => fetch("/api/contributions").then(r => r.json());Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| api-url | string | — | Endpoint returning HeatmapData JSON |
| cell-size | number | 10 | Cell width/height in px |
| cell-gap | number | 3 | Gap between cells in px |
| cell-radius | number | 2 | Cell border radius in px |
| show-total | "true"/"false" | "true" | Show "N contributions in the last year" |
| show-legend | "true"/"false" | "true" | Show Less / More legend |
| show-month-labels | "true"/"false" | "true" | Show month labels above the grid |
| show-day-labels | "true"/"false" | "true" | Show Mon / Wed / Fri labels |
| label | string | "Contribution heatmap" | aria-label for the grid |
Properties (JS only)
| Property | Type | Description |
|---|---|---|
| data | HeatmapData | Set data directly — triggers an immediate render |
| fetchData | () => Promise<HeatmapData> | Custom async data resolver — shows skeleton while loading |
Events
document.querySelector("git-heatmap").addEventListener("day-click", (e) => {
const { date, count } = e.detail; // { date: "2025-06-01", count: 5 }
console.log(date, count);
});On touch devices, tapping a cell also shows a persistent tooltip below the grid — tap again to dismiss.
HeatmapData JSON shape
This is the format your api-url endpoint must return:
{
"totalContributions": 312,
"source": "github",
"weeks": [
{
"days": [
{ "date": "2025-01-05", "count": 0, "level": 0 },
{ "date": "2025-01-06", "count": 3, "level": 1 },
{ "date": "2025-01-07", "count": 8, "level": 2 },
{ "date": "2025-01-08", "count": 14, "level": 3 },
{ "date": "2025-01-09", "count": 22, "level": 4 },
{ "date": "2025-01-10", "count": 1, "level": 1 },
{ "date": "2025-01-11", "count": 0, "level": 0 }
]
}
]
}Use
buildHeatmapDataon your server to generate this from raw{date, count}pairs.
Theming via CSS variables
All variables can be set on git-heatmap or any ancestor element.
git-heatmap {
/* contribution level colors */
--ghm-color-l0: rgba(255,255,255,0.08); /* empty cells */
--ghm-color-l1: #1c3d06;
--ghm-color-l2: #3a7510;
--ghm-color-l3: #6ab81e;
--ghm-color-l4: #aafd35;
/* text & labels */
--ghm-text: rgba(255,255,255,0.5);
--ghm-font: inherit;
--ghm-fs: 11px;
/* tooltip */
--ghm-tooltip-bg: #1c2128;
--ghm-tooltip-border: rgba(255,255,255,0.1);
--ghm-tooltip-text: rgba(255,255,255,0.75);
/* selected cell border */
--ghm-selected: rgba(255,255,255,0.7);
/* loading skeleton opacity */
--ghm-skeleton-opacity: 0.4;
}GitHub dark theme
git-heatmap {
--ghm-color-l0: #161b22;
--ghm-color-l1: #0e4429;
--ghm-color-l2: #006d32;
--ghm-color-l3: #26a641;
--ghm-color-l4: #39d353;
--ghm-text: rgba(255,255,255,0.5);
--ghm-tooltip-bg: #1c2128;
--ghm-tooltip-border: rgba(255,255,255,0.1);
--ghm-tooltip-text: rgba(255,255,255,0.8);
--ghm-selected: rgba(255,255,255,0.6);
}Light theme
git-heatmap {
--ghm-color-l0: #ebedf0;
--ghm-color-l1: #9be9a8;
--ghm-color-l2: #40c463;
--ghm-color-l3: #30a14e;
--ghm-color-l4: #216e39;
--ghm-text: rgba(0,0,0,0.5);
--ghm-tooltip-bg: #fff;
--ghm-tooltip-border: #d0d7de;
--ghm-tooltip-text: #24292f;
--ghm-selected: rgba(0,0,0,0.4);
}Related packages
@rsalianto/git-heatmap-core— Core utilities and fetchers@rsalianto/git-heatmap-react— React component@rsalianto/git-heatmap-vue— Vue 3 component@rsalianto/git-heatmap-next— Next.js App Router route handlers
