Stedefast

Footnotes Sidenotes

2 min read

Footnotes Sidenotes

/plugin-footnotes transforms standard GFM footnotes ([^1]) from a bottom-of-page list into elegant sidenotes displayed in the page margin — a typographic pattern popularised by Tufte CSS and used widely in long-form writing.

On narrow viewports (below collapseBreakpoint) the plugin gracefully falls back to the standard footnote layout produced by remark-gfm.

Installation

pnpm add /plugin-footnotes

Setup

// stedefast.config.ts
import { defineConfig } from "@stedefast/core";
import { FootnotesPlugin } from "/plugin-footnotes";

export default defineConfig({
  // ...
  plugins: [
    FootnotesPlugin({
      position: "right",
      collapseBreakpoint: 1200,
      sidenoteWidth: 260,
    }),
  ],
});

Writing Footnotes

Use standard GFM footnote syntax — remark-gfm must be active in your pipeline (it is by default):

The Stedefast build pipeline runs in seven stages.[^1]

Modules are the secret sauce.[^2] They bridge the static/dynamic gap elegantly.

[^1]: Config → Content → Module Export + Asset Pipeline (parallel) → Render → CF Functions → Manifest.
[^2]: Each module implements `buildStaticExport()` for build-time JSON and `workerHandlers` for edge mutations.

On wide screens, the footnotes appear in the right margin, vertically aligned with their inline reference. On narrow screens, they are shown at the bottom as usual.

How It Works

The plugin is a pure headAssets injection — no rehype tree transformation required.

  1. At build time, Stedefast injects a small <style> block and a <script> block into every page's <head>.
  2. On page load, the script finds the <section data-footnotes> element added by remark-gfm.
  3. For each footnote reference link (<a data-footnote-ref>), the script creates a <span class="sf-fn-sidenote"> adjacent to the reference and moves the footnote content into it.
  4. CSS positions the sidenote in the margin (absolute, right of the article) on wide screens, and hides it on narrow screens.

Requirements

  • remark-gfm must be active (Stedefast enables it by default via /content)
  • Your article element should have position: relative and enough right/left margin for the sidenotes (typically margin-right: 280px on the article when position: "right")

Options

Option Type Default Description
position "right" | "left" "right" Which side of the article to show sidenotes
classPrefix string "sf-fn" CSS class prefix for all injected elements
collapseBreakpoint number 1200 Viewport width (px) below which sidenotes collapse to bottom footnotes
sidenoteWidth number 260 Width of the sidenote column in pixels

CSS Customisation

The plugin uses CSS custom properties you can override in your theme's global.css:

:root {
  --sf-fn-width: 260px;
  --sf-fn-gap: 20px;
  --sf-fn-color: #666;
  --sf-fn-border-color: #e2e8f0;
  --sf-fn-font-size: 0.85em;
  --sf-fn-line-height: 1.5;
}

For dark mode, override in your dark theme selector:

[data-theme="dark"] {
  --sf-fn-color: #9ca3af;
  --sf-fn-border-color: #374151;
}

Responsive Behaviour

Viewport Behaviour
collapseBreakpoint Sidenotes in margin, bottom footnotes section hidden
< collapseBreakpoint Sidenotes hidden, standard bottom footnotes shown

The prefers-reduced-motion media query is respected — no transitions are applied.

Article Margin

For right sidenotes to show without overlapping content, your article wrapper needs sufficient right margin. A Tailwind example:

// theme/layouts/default.tsx
<article className="mx-auto max-w-2xl px-4 xl:mr-72">
  {/* sidenotes will appear in the xl:mr-72 gutter */}
  {children}
</article>