Demonstration.mov
An Obsidian plugin for adaptive marginalia — Tufte/Cornell-style side notes that live in the page margins on wide screens and gracefully fall back to compact, embedded note boxes when space is tight.
Write a note once with a simple callout, and Marginalius decides how to present it based on the available width of the editor pane.
- Two adaptive layouts from one syntax:
- Cornell / margin view (wide panes): the note is pulled out of the text column into the side gutter, borderless and muted, like a printed margin note.
- Embedded view (narrow panes): the note becomes a compact, rounded, floated box that sits inline with the text.
- Left and right margins:
[!margin]floats into the left gutter,[!margin-r]into the right. - Responsive width: in the wide view the note width is computed from the actual gutter space, so resizing the pane (or opening a sidebar) shrinks the note to stay flush against the pane edge instead of being clipped. When the gutter gets too small it automatically switches to the embedded view.
- Word-safe wrapping: text in a narrow margin never splits mid-word. Non-breaking spaces in your notes (commonly typed with
Option+Spaceon macOS, or pasted from rich text) are normalized at render time so phrases wrap on real word boundaries — your source file is never modified. - Click-to-edit: clicking a rendered margin note in the editor places the cursor at that note's position in the document.
- Configurable widths and spacing via a settings tab.
- Theme-friendly: uses theme variables (text colors, borders, readable line width) and works in both Reading view and Live Preview.
Use a callout with the margin (left) or margin-r (right) type:
> [!margin]
> Result: only the mysql-backup pod can assume that role and write to S3;
> other pods cannot. So yes: it's access control and least privilege.
Your main body text goes here. On a wide screen the note above is rendered
in the left margin next to this paragraph.
> [!margin-r]
> This note is pulled into the right-hand margin instead.- On a wide pane the notes appear in the margins, borderless and muted.
- On a narrow pane the same notes render as compact, rounded boxes floated into the text.
Settings → Community plugins → Marginalius
| Setting | Description | Default |
|---|---|---|
| Sidenote width | Maximum width of a margin note in the wide (Cornell) view. The note may render narrower if the gutter is smaller than this. | 200px |
| Sidenote margin | Gap between a margin note and the main document text. | 20px |
| Intrusive width | Width of the embedded note box in the narrow (half-embedded) view. | 200px |
These map to the CSS custom properties --marginalius-width, --marginalius-margin, and --marginalius-intrusive-width.
Marginalius is intentionally small and split into focused modules under src/:
main.ts— plugin lifecycle. Loads settings, injects the dynamic CSS variables from settings, registers the wrap fix, and wires up the click-to-edit handler.settings.ts— settings interface, defaults, and the settings tab.wrap-fix.ts— a markdown post-processor that replaces non-breaking characters (U+00A0,U+202F,U+2007, the word joiner/ZWNBSP, and the non-breaking hyphen) with their breaking equivalents inside margin callouts only, so narrow notes can wrap normally. It runs for both Reading view and Live Preview.styles.css— all presentation:- Strips the default callout chrome (title, icon, border, background) for
margin/margin-r. - Forces word-integrity wrapping (
word-break: normal,overflow-wrap: break-word) across the callout and its descendants, including the CodeMirror internals used in Live Preview. - Defines the narrow / embedded layout as the default.
- Uses a CSS container query on the markdown view (
container-type: inline-size) to switch to the wide / Cornell layout atwidth >= 1000px.
- Strips the default callout chrome (title, icon, border, background) for
The body is centered at the readable line width (--file-line-width), leaving a gutter on each side. Using container query units, the plugin computes:
gutter = (100cqi - var(--file-line-width)) / 2
fit = max(0, min(configured width, gutter - margin - edge))
fit drives both the note's width and its negative pull-out margin, so the box and its offset always stay in sync. As the pane narrows, fit shrinks; below the breakpoint the note reverts to the embedded layout. Reading view adds a small extra --marginalius-edge of separation because its rendered text sits a little closer to the gutter than the editor's.
Note: the wide view relies on Readable line length being enabled (the default), which is what creates the side gutters.
Requirements: Node.js 18+ and npm.
# install dependencies
npm install
# development build with watch
npm run dev
# production build (type-check + bundle)
npm run buildThe build type-checks with tsc and bundles src/main.ts into main.js with esbuild (see esbuild.config.mjs).
Copy the release artifacts into your vault's plugin folder, then reload Obsidian and enable the plugin in Settings → Community plugins:
cp main.js manifest.json styles.css "<Vault>/.obsidian/plugins/obsidian-marginalius/"Required artifacts: main.js, manifest.json, styles.css.
Marginalius runs entirely locally. It makes no network requests, collects no telemetry, and never modifies your notes on disk — the non-breaking-space normalization only affects the rendered DOM.
MIT