2DPersonal progressGuide 03

Habit tracker heatmaps for goals and routines

Compare progress toward several daily goals without flattening every habit into a single streak.

A fortnight of daily habits

Example data
ReadRunMeditateWalkPractice
MTWTFSSMTWTFSS
lessmoreno data
5 habits ยท 14 daysHover or focus a cell for details
Rows
Habit
Columns
Day
Value
Progress toward a goal

The pattern

What the data tells you

Ring thickness makes partial progress visible. The unlogged Sunday is separate from a skipped habit.

Use one row per habit and one column per day. Rings or compact cells show progress toward a goal, while unknown days can stay visibly separate from days where the person chose not to complete the habit.

A habit tracker is more useful when it distinguishes skipped, completed, and unlogged days. heatmap-ui gives each state a place in the visual model and lets the product choose whether progress is shown by colour, size, or both.

Build it in React

From data to heatmap

TypeScript / React

Prepare your data

A row-and-column matrix of percentages, minutes, or another normalized measure of progress toward a goal.

Make the component yours

Start with this example. Adjust the labels, colours, and tooltips to fit your product.

habit-tracker.tsx
import { Heatmap } from "@thilakbhat/heatmap-ui";
import "@thilakbhat/heatmap-ui/styles.css";

// Percent of each daily goal. 0 = logged but skipped; null = not logged.
const progress = [
  [90, 75, 100, 0, 82, 68, null],
  [40, 60, 0, 85, 92, 71, null],
];

export function HabitTracker() {
  return (
    <Heatmap
      rows={2}
      columns={7}
      values={progress}
      shape="ring"
      colors={["#4c0519", "#9f1239", "#e11d48", "#fda4af"]}
      unknownOpacity={0.3}
      rowLabels={["Read", "Run"]}
      tooltip={(cell) => (cell.known ? `${cell.value}% of goal` : "Not logged")}
      ariaLabel="Progress toward daily habits"
    />
  );
}
Key props
Heatmapshape="ring"unknownOpacitynull for unlogged
API reference

A few more details

Common questions

Habit tracker heatmaps, explained.

Is a heatmap a good format for tracking habits?

A habit heatmap is useful when people need to compare several routines across the same days. Rows represent habits and colour or ring progress shows how consistently each goal was completed.

How do I distinguish a missed habit from an unlogged day?

Use a confirmed zero for a missed or incomplete habit and known: false for a day that was never recorded. The two states should not share the same visual treatment.

Can a habit heatmap display percentages or minutes?

Yes. Normalize each habit to a comparable percentage, minute total, or goal ratio, then use a ring or another heatmap shape to show progress toward the target.

How do I create a habit tracker heatmap in React?

Store progress as a row-and-column matrix and pass it to heatmap-ui's Heatmap component with row labels, a goal-friendly colour ramp, and an accessible ariaLabel.