<side-note>

Tufte-style sidenotes for the modern web — as a single HTML element.

What it is

<side-note> is a custom HTML element A custom element is part of the Web Components spec — a way to register your own HTML tags directly with the browser. No framework required. that turns inline content into a sidenote in the page margin. Authors write the note exactly where they want the marker to appear in the prose; the component places a numbered superscript at that position and floats the note's body out into the gutter alongside the paragraph.

The convention is centuries old. The earliest surviving examples appear in 8th-century Irish gospel books, with both scribal corrections and devotional commentary in the margins. Margins were once a primary site of intellectual work — corrections, cross-references, commentary, doubt — before footnotes pushed them to the bottom of the page in the early modern era. Edward Tufte's work on information design Tufte's The Visual Display of Quantitative Information (1983) reintroduced sidenotes to a generation of designers who'd grown up with footnotes-by-default. revived them for serious readers in the 1980s, and the convention has since spread from print into the Tufte-CSS family of stylesheets that inspired this component.

There's no framework requirement. Demonstrating side="left". Notes can land on either margin — the attribute uses logical sides, so dir="rtl" flips them automatically. The element registers itself directly with the browser via the Custom Elements API and works inside any HTML page, whether you're writing React, Astro, plain hand-coded HTML, or none of the above.

Design choices

Each note is rendered inside an open shadow root "Open" so authors can inspect the rendered output during debugging. Closed shadow roots block external inspection without offering a meaningful security benefit for a presentation component. with two structural pieces: a <span> for the superscript marker, and an <aside> for the note's body. The <aside> is HTML's semantic wrapper for tangentially related content, and screen readers announce it appropriately.

Numbering uses CSS counters A counter-reset: sidenote on the container and counter-increment: sidenote on each note element. The counter value is read by both the marker and the margin note, keeping them visually in sync without any JavaScript bookkeeping. rather than a JavaScript counter, which means numbers stay correct regardless of how nodes are inserted, rendered, or hydrated. Authors who need a custom marker — an asterisk A custom label="*" overrides the auto-incremented number. Useful for editorial notes that should read distinct from numbered citations. or a dagger, say — can override per-note via the label attribute.

For positioning, the note is absolutely positioned against the nearest .has-sidenotes ancestor, The container needs position: relative and reserves a right-side gutter via padding-inline-end. The component injects this stylesheet into the document head once on first connect — no setup required beyond adding the wrapper class. which gives the note a stable visual anchor relative to the paragraph while leaving the source DOM untouched. No reparenting; the element you wrote in the prose is the element the browser renders.

Authoring

Wrap a prose container in class="has-sidenotes" and drop the element inline:

<article class="has-sidenotes">
  <p>
    Some prose
    <side-note>A note in the margin.</side-note>
    continues on.
  </p>
</article>

The note's body accepts any inline content Including links, inline code, emphasis, and any other phrasing content the author needs. Styling stays consistent because the host inherits the document's font. — links, code, emphasis, anything that makes sense alongside a paragraph.

Notes are responsive without any JavaScript: at narrow viewports they flow inline as italic parentheticals after their markers, and at wide viewports they float into the margin. Resize this window narrower than about 60rem (roughly 960px) to watch the notes return to the prose flow. The switch is pure CSS — no popover toggle, no tap to reveal, no scroll listener. Authors who want a particular note to always read inline regardless of viewport can opt in per note Like this one: the inline attribute keeps the note in the flow of the prose at any width. Handy for short asides that don't need full marginal treatment. via the inline attribute.