Monthly habit calendar
Dashy vault/Guides/Monthly habit calendar
Guides/Monthly habit calendar.md

A monthly habit calendar in Obsidian, without Dataview

Properties
blocks
heatmap
keys
range: monthlayout: calendarlayers
needs dataview
checked on
Dashy 2.0.0

A year of tiny squares is good for the long view. For this month you want a calendar: the day numbers in weekday columns, and a dot under every day you kept the habit. One heatmap block draws it from the checkboxes in your daily notes. Give it a few habits and each gets a dot in its own colour.

This month as a calendar: the month and year on top, weekday columns, each day's number with an orange, green or purple dot for gym, reading and meditation, today ringed, the days ahead dimmed, and a legend with the three habits
What you have at the end of step 3. From a demo vault with a year of daily notes.

1A checkbox per habit

One checkbox property per habit in each daily note. In a daily note, add a property, set its type to Checkbox, and name it after the habit.

Diary/2026-10-02.md
---
gym: true
read: false
meditate: true
---

## 2026-10-02
  • 2026-10-02The note's name is its date. Anything after the date is fine: 2026-10-02 Friday counts too.
  • gym: trueA ticked box puts a dot under that day. An unticked one, or none at all, leaves the day bare.
  • DiaryThe folder the block reads from. Use the one your daily notes already live in.

2One habit, one month

Make a note, say Habits.md, and paste this block.

Habits.md
```heatmap
source: Diary
field: gym
color: orange
range: month
layout: calendar
```
  • range: monthThe month you are in, from the 1st to its last day. The days still ahead are there too, dimmed and without dots.
  • layout: calendarDraw it as a calendar: the month and year on top, a column per weekday, and each day's number. The week starts where your language starts it.
  • field: gymThe habit. Each note that ticked it puts a dot under its day.
  • Captiongym: 4 of 6 days on the 6th: the days with a dot, out of the days so far this month, today included.

Today has a ring around it. Hover a day for its date, the value and the note it came from. A day with a dot is a link: click it and its note opens. On a phone, the first tap shows the same text under the calendar, and a second tap opens the note.

The dots count notes, not ticks. Two notes on one day, a morning and an evening one, give that day two dots. A day never shows more than three.

3Several habits, a dot each

Swap field for layers, one line per habit. This block draws the picture above.

Habits.md
```heatmap
source: Diary
range: month
layout: calendar
layers:
  - { field: gym, color: orange, label: Gym }
  - { field: read, color: green, label: Reading }
  - { field: meditate, color: purple, label: Meditation }
```
  • layersOne line per habit, in place of field. A day gets a dot for every habit ticked in its note, in the order of the list. Up to four dots fit under a day.
  • colorPer habit: blue, green, cyan, purple, pink, orange, red, gray or #rrggbb. Leave it out and the next free colour is picked.
  • labelThe name in the legend under the calendar and in the tooltip. Without it, the property name.
  • CaptionCounts the days with at least one dot: Gym, Reading, Meditation: 5 of 6 days.

The tooltip lists every habit in that day's note, ticked or not, as in Gym 1, Reading 0, Meditation 1.

Every habit shows

On the year grid, a day with two habits has room for one colour, and the first layer or pick: max decides which. The calendar has a dot for each, so pick does not change the dots.

4This week, and days off

For a single row, the week you are in, write range: week. skip_field marks the days you were off.

Habits.md
```heatmap
source: Diary
field: gym
color: orange
range: week
layout: calendar
skip_field: vacation
```
  • range: weekSeven days, from the first day of your week to the last. When the week runs into the next month, the heading names both: Sep 2026 to Oct 2026.
  • skip_field: vacationA day whose note sets vacation: true is hatched, dot or no dot, and the legend explains the hatch. The caption's count does not change.
  • Days aheadA note for next Friday with vacation: true hatches that day already. Anything else in it waits: a day ahead gets no dot.

The whole note

The blocks from steps 3 and 4, ready to paste into an empty note: the month with every habit, and this week of gym under it.

Habits.md
```heatmap
source: Diary
range: month
layout: calendar
layers:
  - { field: gym, color: orange, label: Gym }
  - { field: read, color: green, label: Reading }
  - { field: meditate, color: purple, label: Meditation }
```

```heatmap
source: Diary
field: gym
color: orange
range: week
layout: calendar
skip_field: vacation
```

Ask your agent

With Dashy's skill installed, an AI agent can write this from a request in plain words: it looks at your property names and folders first, then writes the blocks. Open the note in Reading view and paste any error a block shows back to the agent.

Prompt
In a new note called Habits, show this month as a calendar from my daily notes, with a dot under each day I went to the gym, read or meditated, each habit in its own colour. Under it, this week's gym days the same way, with the days I marked as vacation shown as days off.

What comes back is something like the note above. The agent's YAML may differ from the guide's, with your own property names and labels, but it should do the same, and this guide is the reference to compare it against. More on working with an agent.

What it does not do

A month or a week, dots only, always now
  • Only a month or a week. With range: year, range: 90d or no range at all, layout: calendar shows a warning and the block draws the grid instead.
  • No shading. A dot is a dot: 1 km and 12 km look the same. bands has nothing to shade and warns that it is ignored. For how much, use the grid.
  • Always the month you are in. There are no arrows to step back to last month. For the months behind you, put a grid next to it, as in the first variation below.

The same calendar with Tracker or dataviewjs

Both read the same daily notes. The Heatmap Calendar plugin is the other name people search for. It draws a whole year from a dataviewjs script you write, and a month on its own was asked for in its issue #7.

With the Tracker plugin
```tracker
searchType: frontmatter
searchTarget: gym, read, meditate
folder: Diary
datasetName: Gym, Reading, Meditation
month:
    startWeekOn: 'Mon'
```
  • Tracker's calendar is a month view too, one month at a time.
  • It shows one habit at a time. Click its name in the header to switch to the next.
With Dataview, JavaScript queries turned on
```dataviewjs
const done = new Set(dv.pages('"Diary"')
  .where(p => p.file.day && p.gym === true)
  .map(p => p.file.day.toISODate())
  .array());

const first = dv.luxon.DateTime.now().startOf("month");
const rows = [];
let week = Array(first.weekday - 1).fill("");
for (let d = first; d.month === first.month; d = d.plus({ days: 1 })) {
  week.push(d.day + (done.has(d.toISODate()) ? " ●" : ""));
  if (week.length === 7) { rows.push(week); week = []; }
}
if (week.length) rows.push(week.concat(Array(7 - week.length).fill("")));
dv.table(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], rows);
```
  • Needs Enable JavaScript queries in Dataview's settings. It is off by default.
  • A table with a dot for one habit. Monday first, as written. Colours, a second habit, today's ring, links to the notes and the count are more code.
DashyTrackerdataviewjs
Several habits on one dayA dot each, in its colourOne at a time, click to switchWrite it
First day of the weekYour language'sstartWeekOnMonday, as written
Other monthsNo, this month onlyOne month at a timeWrite it
What you installDashyTrackerDataview, JavaScript queries on

Variations

The months behind you

The calendar for this month, a grid of the last half year under it. Same notes, same colour.

heatmap
```heatmap
source: Diary
field: gym
color: orange
range: month
layout: calendar
```

```heatmap
source: Diary
field: gym
color: orange
range: 182d
```

A number instead of a checkbox

Any number in the note puts a dot under its day, even 0. Hover for the value: the dot stays the same size.

heatmap
```heatmap
source: Diary
field: run_km
color: green
range: month
layout: calendar
```

A note per workout

Notes named 2026-10-02 Run and 2026-10-02 Swim land on the same day: two dots. A third adds a third, and there it stops.

heatmap
```heatmap
source: Workouts
field: minutes
color: red
range: month
layout: calendar
```

Your own heading

title replaces the caption, count included. The month and year above the days stay.

heatmap
```heatmap
source: Diary
field: meditate
color: purple
range: month
layout: calendar
title: Meditation this month
```

If a block shows an error

A block that cannot draw what you asked for says why, inside the note. The ones you are likely to see here:

  • layout: calendar needs range: month or range: week. The range line is missing or says something else. The grid is drawn until you fix it.
  • bands is ignored with layout: calendar. Delete the bands line. A day shows dots, not a shade.
  • layout expects grid or calendar. A typo, such as layout: calender. The grid is drawn instead.
  • "meditate" never contributed a value here. One habit has no dots at all: its name is spelled differently in the block and in the notes, or those notes are in another folder.