Skip to content

stamat/marked-github-footnote

Repository files navigation

marked-github-footnote npm version

A lightweight, zero-dependency marked extension that renders GitHub-style footnotes ([^1]) the way GitHub actually does.

Instead of grabbing footnote bodies with a single regex and patching the output with string heuristics, it scans definitions line by line the way marked's own list tokenizer does. That buys correct handling of the cases other footnote extensions get wrong:

  • Tab-indented continuation lines stay inside the footnote (tabs expand to 4-column stops, per CommonMark)
  • Lazy paragraph continuation joins the footnote paragraph, and headings/fences/lists correctly interrupt it
  • Multi-block bodies (paragraphs, lists, fenced code with blank lines) are de-indented and handed to the block lexer whole — no last-line guessing
  • Labels never reach HTML attributes unencoded — no attribute-injection XSS via [^label]
  • Footnotes are numbered and ordered by first reference, labels match case-insensitively, unreferenced definitions are omitted — all GitHub behavior

Installation

npm install marked-github-footnote

Requires marked >= 12.

Usage

import { marked } from "marked";
import { markedGithubFootnote } from "marked-github-footnote";

marked.use(markedGithubFootnote());

const html = marked.parse(markdown);

Given this Markdown:

Here is a footnote reference[^1], and another[^long].

[^1]: The first footnote.

[^long]: A footnote with multiple lines.

    Indented lines belong to the same footnote.

    - even lists
    - work here

You get this HTML:

<p>
  Here is a footnote reference<sup
    ><a
      href="#fn-1"
      id="fnref-1"
      data-footnote-ref
      aria-describedby="footnote-label"
      >1</a
    ></sup
  >, and another<sup
    ><a
      href="#fn-long"
      id="fnref-long"
      data-footnote-ref
      aria-describedby="footnote-label"
      >2</a
    ></sup
  >.
</p>
<section data-footnotes role="doc-endnotes">
  <h2 class="sr-only" id="footnote-label">Footnotes</h2>
  <ol>
    <li id="fn-1">
      <p>
        The first footnote.
        <a
          href="#fnref-1"
          data-footnote-backref
          aria-label="Back to reference 1"
          ></a
        >
      </p>
    </li>
    <li id="fn-long">
      <p>A footnote with multiple lines.</p>
      <p>Indented lines belong to the same footnote.</p>
      <ul>
        <li>even lists</li>
        <li>work here</li>
      </ul>
      <a
        href="#fnref-long"
        data-footnote-backref
        aria-label="Back to reference 2"
        ></a
      >
    </li>
  </ol>
</section>

Options

Option Default Description
prefixId "" Prepended to every generated id. Use "user-content-" to reproduce GitHub's ids verbatim.
heading "Footnotes" Text of the visually hidden footnotes section heading.
backRefLabel "Back to reference {0}{1}" aria-label template for back-reference links. {0} is the reference number, {1} is the suffix (e.g. "-2"). Supports i18n.

Why this instead of marked-footnote?

marked-footnote is the official marked extension for footnotes. marked-github-footnote differs in several important ways:

  • Correct tab expansion: Tabs expand to 4-column stops per CommonMark, not simply replaced with 4 spaces. A tab at column 2 only advances to column 4 — that should not count as a 4-space indent. marked-footnote gets this wrong.
  • Lazy paragraph continuation: Blank lines between paragraphs inside a footnote definition are preserved, and unindented text continues the paragraph. marked-footnote has no support for this.
  • Paragraph interruption detection: Headings, fences, blockquotes, lists, and HTML blocks correctly break footnote definitions. marked-footnote does not detect these.
  • Case-insensitive labels: [^Note] matches [^note]: ..., like GitHub. marked-footnote is case-sensitive.
  • First-reference ordering: Footnotes are numbered by first appearance in text, not definition order. marked-footnote uses definition order.
  • Labels never become HTML text: Labels only appear in URL-encoded attributes, reducing XSS surface. marked-footnote can render raw label text.

If you need GitHub-fidelity footnotes, use marked-github-footnote. If you need more configuration options (custom CSS classes, <hr> divider, bracket markers like [1]), use marked-footnote.

License

MIT

About

A lightweight, zero-dependency marked extension that renders GFM footnotes the way GitHub actually does.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors