@peaceroad/markdown-it-footnote-here
v0.5.0
Published
A markdown-it plugin. This generate aside[role|doc-footnote] element just below the footnote reference paragraph.
Readme
markdown-it-footnote-here
This is markdown-it plugin. And, this plugin is a further fork of markdown-it-footnote-here, which is a fork of the original markdown-it-footnote plugin.
This plugin inserts footnotes just below paragraphs.
The input Markdown and the output HTML are as follows.
Markdown:
A paragraph.[^1]
[^1]: A footnote.
A paragraph.HTML:
<p>A paragraph.<a href="#fn1" id="fn-ref1" class="fn-noteref" role="doc-noteref">[1]</a></p>
<aside id="fn1" class="fn" role="doc-footnote">
<p><a href="#fn-ref1" class="fn-backlink" role="doc-backlink">[1]</a> A footnote.</p>
</aside>
<p>A paragraph.</p>Notice.
- When multiple instances of the same footnote number appear in the main content, the default behavior is that the backlink from the footnote will refer to the first instance.
- Endnotes default to a trailing backlink style, and repeated endnote references render backlinks for all occurrences with visible
a,b,c, ... suffix markers. - When the same footnote/endnote label is defined multiple times, behavior is controlled by
duplicates.policy(default:warn). - When a note starts or ends with a non-paragraph block such as a list, heading, blockquote, or fence, the plugin inserts standalone label/backlink paragraphs as needed so numbering and return links remain visible.
Endnotes
When a footnote label starts with endnotes.prefix (default: en-), it is collected at the end of the document and rendered as endnotes. The reference/backlink label for endnotes uses references.endnote.prefix (default: E), so endnotes appear as [E1], [E2], ... By default, endnotes render the visible label at the start of the note body and the return link at the end.
Markdown:
A paragraph.[^en-1]
[^en-1]: A endnote.
A paragraph.HTML:
<p>A paragraph.<a href="#en1" id="en-ref1" class="en-noteref" role="doc-noteref">[E1]</a></p>
<p>A paragraph.</p>
<section aria-label="Notes" id="endnotes" role="doc-endnotes">
<ol>
<li id="en1">
<p><span class="en-label">[E1]</span> A endnote. <a href="#en-ref1" class="en-backlink" role="doc-backlink" aria-label="Back to reference E1">↩</a></p>
</li>
</ol>
</section>Use
import mdit from 'markdown-it'
import mditFootnoteHere from '@peaceroad/markdown-it-footnote-here'
const md = mdit().use(mditFootnoteHere)
md.render(/*...*/) // See examples aboveInstall
npm install @peaceroad/markdown-it-footnote-hereOptions
- Breaking change: options are now grouped into
references,backlinks,endnotes, andduplicates. - Removed legacy keys now throw at plugin setup. This includes the old top-level keys such as
beforeSameBacklink,afterBacklink*,labelBra,labelKet,labelSupTag,backLabelBra,backLabelKet,endnotesPrefix,endnotesLabelPrefix,endnotesSection*,duplicateDefinition*,injectErrorStyle, and the old sharedbacklinks.content,backlinks.duplicateMarker,backlinks.trailingLabel,backlinks.ariaLabelPrefix. references(object): controls how note references render in main text.footnote.prefix/endnote.prefix: visible label prefix before the note number. Defaults are''for footnotes and'E'for endnotes.footnote.brackets.open/.close,endnote.brackets.open/.close: visible brackets around note reference labels. Default:'['and']'.footnote.wrapInSup/endnote.wrapInSup: whether that kind of note reference is wrapped in<sup>. Default:false.
backlinks(object): controls labels and return links inside note bodies.footnote.position/endnote.position:'before' | 'after' | 'both' | 'none'(defaults: footnotes'before', endnotes'after').footnote.duplicates/endnote.duplicates:'first' | 'all'(defaults: footnotes'first', endnotes'all').allrenders one backlink per repeated reference;firstpoints back only to the first occurrence.footnote.brackets.open/.close,endnote.brackets.open/.close: visible brackets used for leading note labels/backlinks. Default:'['and']'.footnote.content/endnote.content: trailing backlink content. Default:'↩'.footnote.duplicateMarker/endnote.duplicateMarker: visible duplicate suffix style,'alpha' | 'numeric'(default:'alpha').footnote.trailingLabel/endnote.trailingLabel: whether trailing backlinks render a visible duplicate suffix marker,'none' | 'marker'(defaults: footnotes'none', endnotes'marker').footnote.ariaLabelPrefix/endnote.ariaLabelPrefix: prefix for trailing backlinkaria-labelvalues (default:'Back to reference ').- Note: when
positionincludesbeforeandduplicatesisall, duplicate references and leading backlinks use visible suffixes such asa,b,c(or1,2,3whenduplicateMarker: 'numeric'). - Note: default endnotes use trailing backlinks with visible suffix markers, so repeated endnote references render return links such as
↩a,↩b,↩c. - Note:
position: 'none'still renders a non-link note label so the note number remains visible.
endnotes(object): controls how endnotes are detected and where they are rendered.prefix: prefix that marks a note as an endnote (default:'en-'). When empty, endnotes are disabled.section.id:idattribute for the endnotes section wrapper; omitted when empty (default:'endnotes').section.className:classattribute for the endnotes section wrapper; omitted when empty (default:'').section.label: used asaria-labelwhensection.useHeadingisfalse; used as heading text whensection.useHeadingistrue(default:'Notes').section.useHeading: iftrue, render a heading tag and omitaria-label. Iffalse(default), omit the heading and setaria-labelwhen provided.section.headingLevel: heading level used whensection.useHeadingistrue, limited to1..6(default:2).
duplicates(object): controls duplicate note-definition handling.policy:'warn' | 'ignore' | 'strict'(default:'warn').'warn': keep first definition, mark note block withfootnote-error, mark backlinks withfootnote-error-backlink, and prepend<span class="footnote-error-message">...</span>in note content.'ignore': keep first definition and do not add warning classes/messages.'strict': throw an error on duplicate label.message: warning text used whenpolicyis'warn'(default:'[Duplicate footnote label detected. Using the first definition.]').injectStyle: iftrueandpolicyis'warn', inject a<style>block once per document for.footnote-error-messageand.footnote-error-backlink(includesprefers-color-schemeandforced-colorshandling). Default:false.
- Example:
const md = mdit().use(mditFootnoteHere, {
references: {
footnote: {
brackets: { open: '[', close: ']' },
},
endnote: {
prefix: 'E',
brackets: { open: '[', close: ']' },
},
},
backlinks: {
footnote: { position: 'before', duplicates: 'first' },
endnote: { position: 'after', duplicates: 'all', content: '↑', trailingLabel: 'marker' },
},
endnotes: {
prefix: 'en-',
section: { label: 'Notes', useHeading: true, headingLevel: 2 },
},
duplicates: {
policy: 'warn',
},
})- Diagnostics: when duplicates are detected under
duplicates.policy: 'warn', details are collected inenv.footnoteHereDiagnostics.duplicateDefinitions. - Security note: option strings used in HTML output are escaped before rendering (labels, aria/id/class values, heading text, backlink content/message).
- Unreferenced note-definition note: when a note definition has no matching reference, the note still renders its visible label, but backlink anchors are omitted so broken
hreftargets are not emitted. env.docIdnote: if provided, it is URL-encoded and applied consistently to note/ref ids to keep links valid and safe.- Reused-render note: repeated renders are stable because duplicate-reference suffixes are fixed during parse, and changing
env.docIdon a reusedenvobject updates generated ids consistently. - Renderer note: hosts may call render paths without a populated
env(for example, inline-only renders). In that case, references render without count-based suffixes; pass a sharedenvduring parse+render to keep counts consistent.
