mrrepac1k downloadsA full calendar in a single Markdown note: month/week/day/agenda views with events, tasks, recurrence, colors, drag-to-reschedule and keyboard control, all stored in one code block.
A calendar that lives in one Markdown file. Drop a ```md-calendar code block
into any note and it renders a switchable month / week / day / agenda calendar —
events and tasks, recurrence, colors, notes, and drag-to-reschedule. The block's body
is a small JSON document, so all the data lives inside that one note; the rest of
the note stays a normal, editable Markdown file. Nothing else is required — it's a
self-contained calendar.
Click the ribbon icon (or run “Open the calendar note”) — it opens your calendar, creating the note on first use. One calendar per vault is the default; enable Multiple calendars in settings to make the button create a new note every time. You can also run “Insert calendar” or type the block yourself anywhere:
```md-calendar
{
"events": []
}
```
Switch to Reading view or Live Preview and the block becomes the calendar. Every change you make in the UI is written straight back into the block.
It stays the calendar, too. In Live Preview an editor normally unfolds a code block into its source as soon as the text cursor lands inside it — reopening a note with the cursor remembered there, or walking into it with an arrow key, would drop you into raw JSON. The cursor is kept out instead, so the calendar stays a calendar. The block's edit pencil and Source mode still open the JSON when you actually want it.
Click the gear in the calendar header to set start/end hours. Turn on Use global hours to inherit the plugin defaults again. Save applies the changes; Cancel discards them. Hour changes support the calendar undo command.
You can also set the preferred hour range for week/day views inside a calendar block:
```md-calendar
{
"settings": {
"view": "week",
"showCompleted": true,
"dayStart": 0,
"dayEnd": 20
},
"events": []
}
```
dayStart accepts integer hours from 0 to 23; dayEnd from 1 to 24.
Omitted or invalid values use the plugin's global settings. The effective end is
always at least one hour after the start. As with the global range, the grid
expands to include events outside these hours so no meeting is hidden.
In week/day views, use − / + or Ctrl + mouse wheel over the time grid to zoom from 50% to 300% in 25% steps. Click the percentage to reset to 100%. Auto (next to +) fits the entire displayed hour range into the current viewport, including hours added for outlying events. It can go below 50% when needed; the mode is remembered and readjusts when the pane or hour range changes. The highlighted Auto button indicates automatic mode. Click it again to stop automatic fitting and keep the exact current scale. Use − / +, Ctrl + wheel, or the percentage reset to return to the regular manual zoom steps. Wheel zoom keeps the time under the pointer in place where scroll limits allow; the buttons keep the middle of the viewport in place. Short event blocks prioritize the title and hide details that no longer fit; very small blocks remain colored markers. Hover or open an event to read its full time, title, and description. Zoom is remembered per calendar block in the plugin's local settings, shared between week/day views, and does not rewrite the Markdown note or change event times.
When entering an event's time, 1:05 means 01:05; compact forms such as 1530
and ranges such as 15-18 also work. Invalid times or incomplete ranges show an
inline hint and keep your input for correction. Overnight ranges such as
23:00–02:00 are supported; equal start and end times are rejected.
The placement time draft survives a calendar redraw or cancelling and restarting
placement with the same title during the current session.
-
(or press Ctrl/Cmd+Enter) to add a task instead — it lands on the picked day
with no time step. Esc or the banner's ✕ cancels and returns your original text to the add bar.You can also enter 15:00–16:00 Meeting or 9:00 Breakfast in the add bar.
A preview shows the recognized time and title before you press Enter; then choose
the day to create the event. The typed time takes priority even if you click an hour
slot. Only an explicit HH:MM prefix is recognized. Ordinary numbers, dates, and
invalid ranges stay in the title; task input is kept verbatim without time parsing.
- (or Ctrl/Cmd+Enter)
in the add bar, the Task toggle in quick create, or Kind: Task in the editor.
An unfinished task never sinks into the past — it carries forward to today,
drawn red, until you complete it (ticking pins it to the day it was done).red, orange, yellow, green,
blue, purple) in the event editor; it adapts to your theme and renders in
every view. The default is your theme's accent color.1500, press Enter to
add. Two Enters (leaving the time empty) makes it an all-day event; the Task
toggle (or Ctrl/Cmd+Enter) adds a task instead. More options… opens the full
editor (kind, repeat, end time, multi-day, color, note). Click an existing event to
edit it; in the full editor Cmd/Ctrl+Enter saves.Drag a non-recurring event (or task) to move it:
Dragging one occurrence of a recurring event moves just that occurrence: the original date is skipped and the moved copy becomes an ordinary standalone event, leaving the rest of the series untouched.
On mobile a long-press starts the drag — the context menu is suppressed for draggable items there (recurring events keep it: they can't be dragged, and it's the way to delete one occurrence on a phone).
The selected day carries a quiet summary — “3 events · 1 task” — on the agenda date line and in the day view's column header (in month view it's the day cell's tooltip). Tasks are counted only while undone: that is the number that still asks something of you. Events are counted as drawn.
On a phone the switcher offers just Agenda and Day — agenda by default (its dotted mini calendar is the month overview). The view saved in the note by your desktop is left untouched: the phone only narrows what it shows, per session.
In week/day views, editing or completing an item preserves your position on the time axis. Changing the date or keyboard hour selection uses the usual navigation; Today returns to the current time.
Every view is keyboard-navigable — the arrow keys or WASD move the selection (physical keys, so they work in any layout). In month and agenda, left/right is ±1 day and up/down ±1 week. In week and day the selection is two-dimensional: it starts on today's all-day band; A/D (←/→) pick the day, W/S (↑/↓) walk down into the hour slots and back up. Enter or Space creates an event on the selection — from an hour slot it carries that time into the dialog. Q/E cycle the view left/right through month → week → day → agenda. PageUp/PageDown switch months (Shift — a year), Home/End jump to the week's edges. T — like the Today button — jumps the selection to today and resets the week/day slot cursor to the all-day band, keeping the grid focused. G goes to a date, F opens search, C copies the period as text. Tab steps into the selected day's items (Enter edits, Space completes, Delete removes, M opens the menu, Escape steps back out). With an item picked, the digits 1–7 set its color (the swatch order of the editor, 1 being the accent) and Shift+arrows move the item itself rather than the cursor: left/right by a day, up/down by a week — or, for a timed item in week/day, up and down slide it by one grid step of time, duration kept. The selection follows the item, so the keys can simply be repeated. A dedicated calendar note (the block is the whole note, as made by the command) focuses the grid on open — the keys work immediately. In a calendar embedded among other text, click or Tab onto the grid first (closing an event dialog also returns focus to the grid). The selection ring shows while the grid holds focus; in agenda the selected day drives the side panel. Ctrl/Cmd+Z anywhere in the calendar undoes the last calendar change, Shift+Z (or Ctrl+Y) redoes — the note editor's own undo history stays untouched. Deletes never ask for confirmation: undo is the safety net, and on mobile the delete notice carries a one-tap Undo button.
Settings: default view (desktop and mobile separately), the first day of the week (Obsidian's locale, or a fixed day), the working-hours window (default 07–22), the duration of a new timed event (default one hour), the drag/resize snap step (15 / 30 / 60 minutes), how many events a month cell shows before “+N more”, the completion chime (a soft synthesized two-note sound on ticking something done — no audio files involved), and the two items below. Times are shown in 24-hour format.
Obsidian's readable line width is right for a paragraph and wrong for a grid: it leaves the calendar in a narrow column with much of the pane empty on either side, ending wherever its content happens to stop. Fill the pane lifts that clamp for a note holding a calendar and gives the block the height left below it, so the month rows, the hour grid and the agenda's day panel grow with the window instead of with the text column. The height is measured, not assumed, and follows a window resize, a sidebar toggle or a split. The setting chooses where this applies — desktop only (the default), mobile only, everywhere, or nowhere — since the two platforms fit differently.
On desktop the fit is exact: the block ends where the pane does, so the note itself has nothing left to scroll. When the calendar is the last thing in the note, its scrollbar goes as well. Write anything below the block and the scrollbar comes back — the calendar gives up exactly the height that text needs rather than covering it. On mobile, where a resize or a sidebar toggle can't recover space the way it can on desktop, the calendar takes the same measured height but is free to grow past it — the note scrolls instead of anything being clipped.
On desktop the status bar shows the next thing in your calendar — 16:00 · Rehearsal
— with the note closed: it reads the calendar note from disk, refreshes every minute and
whenever that note changes, and a click opens the calendar on that day. A timed event
today counts until it finishes (the meeting you're sitting in is still what's
happening); all-day items and tasks count all day, but on today they step aside for a
real appointment still ahead — so an overdue task can't camp there and hide it. Nothing
upcoming means no item at all. Turn it off in settings.
A calendar that lives in one note keeps everything you ever put in it, and years of finished appointments are dead weight in a file you sync. Delete the past (the cleanup action in ⋯, or the Delete past records command) clears out what is over: pick a cut-off — today, a month back, three months, a year, or a date of your own — and it tells you exactly how much would go before you commit. One Ctrl+Z brings the whole sweep back.
What it never deletes: an unfinished task (it carries forward to today, so it is never in the past) and a repeat that is still running — one with no end date, or an end still ahead. A multi-day event is judged by the day it ends on.
Series that stay are still trimmed of their ballast: every skipped occurrence and every completed occurrence recorded behind the cut-off. In a long-running weekly event those accumulated dates are most of what the note is carrying, and none of them can matter again.
The JSON is human-inspectable but meant to be edited through the UI. If you hand-edit
it into invalid JSON, the block shows an error with a Reset block button. An optional
top-level "title" string is shown as a heading above the calendar controls.
Interface follows Obsidian's language (English, or Russian when the app is set to Russian), works on desktop and mobile.
Author: mrrepac · MIT