Skip to main content

How to add a footnotes section to doc pages and blog entries

Daniel Farlow
Software Engineer

This post details how to outfit your Docusaurus site's doc pages and blog posts with a footnotes section.

Overview

Usage considerations

The details outlined in this post are meant to illustrate how to enable footnotes for doc pages and blog posts on your Docusaurus site. As Wikipedia notes, footnotes are notes at the foot of the page — these notes should be supplemental information to the main body of the text, information that should be entirely optional for the reader to consume. This differs from the use of, say, an in-line asterisk with a tool-tip that conveys something important in-place in the main body of the text.[*] Both options have their use. This post details how to use footnotes by means of a package-based solution, namely react-a11y-footnotes.

Package details

As noted in its docs, the react-a11y-footnotes package has a trim API:

  • FootnotesProvider: We will need to swizzle the Docusaurus root to use this effectively.

    a component with no HTML footprint that needs to wrap the content part of your application.

  • FootnoteRef: This is the actual component we will need to use on different doc pages and blog posts whenever we want to have footnotes.

    an inline component wrapping a footnote reference, rendering an anchor link (<a>) to the correct footnote in the footer.

  • Footnotes: This component will be inserted into swizzled Docusaurus components DocItem/Layout and BlogPostItem/Content, resulting in us being able to use footnotes on doc pages and blog posts, respectively.

    a component rendering the actual footnotes, usually placed at the end of the content area.

Default styling for the package can be overriden and customized using CSS. The library provides namespaced data attributes as styling anchors:

  • data-a11y-footnotes-ref: applied to every single footnote reference
  • data-a11y-footnotes-footer: applied to the footnotes wrapper
  • data-a11y-footnotes-title: applied to the footnotes title
  • data-a11y-footnotes-list: applied to the footnotes list
  • data-a11y-footnotes-list-item: applied to every individual footnote
  • data-a11y-footnotes-back-link: applied to every individual back link

The example below shows how the anchors above are targeted on the CodeSandbox demo.

CodeSandbox styling example
* {
box-sizing: border-box;
}

body {
margin: 1em;
font-size: 125%;
line-height: 1.4;
max-width: 600px;
margin: 0 auto;
}

[data-a11y-footnotes-footer] {
margin-top: 2em;
border-top: 1px solid silver;
font-size: 80%;
}

[data-a11y-footnotes-list] {
padding-left: 1.25em;
}

/**
* Initialiazing a `footnotes` counter on the wrapper
*/
body {
counter-reset: footnotes;
}

/**
* Inline footnotes references
* 1. Increment the counter at each new reference
* 2. Reset link styles to make it appear like regular text
*/
[data-a11y-footnotes-ref] {
counter-increment: footnotes; /* 1 */
text-decoration: none; /* 2 */
color: inherit; /* 2 */
cursor: default; /* 2 */
outline: none; /* 2 */
}

/**
* Actual numbered references
* 1. Display the current state of the counter (e.g. `[1]`)
* 2. Align text as superscript
* 3. Make the number smaller (since it's superscript)
* 4. Slightly offset the number from the text
* 5. Reset link styles on the number to show it's usable
*/
[data-a11y-footnotes-ref]::after {
content: "[" counter(footnotes) "]"; /* 1 */
vertical-align: super; /* 2 */
font-size: 0.5em; /* 3 */
margin-left: 2px; /* 4 */
color: blue; /* 5 */
text-decoration: underline; /* 5 */
cursor: pointer; /* 5 */
}

/**
* Resetting the default focused styles on the number
*/
[data-a11y-footnotes-ref]:focus::after {
outline: thin dotted;
outline-offset: 2px;
}

[data-a11y-footnotes-back-link] {
font-size: 80%;
}

/**
* Highlight target note
*/
footer :target {
background: yellow;
}

All we have to do now is actually use the package!

Install footnotes package

Start by installing the react-a11y-footnotes package (see the demo CodeSandbox for an example different from the one included on this post):

npm install react-a11y-footnotes

Swizzling

As noted above, we will need to swizzle the Docusaurus Root, DocItem/Layout, and BlogPostItem/Content components.

Root

As noted in the Docusaurus docs:

The <Root> component is rendered at the very top of the React tree, above the theme <Layout>, and never unmounts. It is the perfect place to add stateful logic that should not be re-initialized across navigations (user authentication status, shopping card state...). Swizzle it manually by creating a file at src/theme/Root.js:

/src/theme/Root.js
import React from 'react';

// Default implementation, that you can customize
export default function Root({children}) {
return <>{children}</>;
}

If we follow the example outlined in the react-a11y-footnotes package documentation, then we will see that the Docusaurus Root is where we need to add the FootnotesProvider:

/src/theme/Root.js
import React from 'react';
import { FootnotesProvider } from 'react-a11y-footnotes'

// Default implementation, that you can customize
export default function Root({ children }) {
return <FootnotesProvider>{children}</FootnotesProvider>;
}

DocItem/Layout

Swizzle the DocItem/Layout component (warnings can be safely ignored since the change is so minor):

npm run swizzle @docusaurus/theme-classic DocItem/Layout -- --eject

Update the index.js file for the swizzled DocItem/Layout component to include the Footnotes component as follows:

/src/theme/DocItem/Layout/index.js
import React from 'react';
// ...
import { Footnotes } from 'react-a11y-footnotes';
// ...
export default function DocItemLayout({ children }) {
// ...
return (
// ...
<article>
<DocBreadcrumbs />
<DocVersionBadge />
{docTOC.mobile}
<DocItemContent>{children}</DocItemContent>
<Footnotes />
<DocItemFooter />
</article>
// ...
);
}

BlogPostItem/Content

Swizzle the BlogPostItem/Content component (warnings can be safely ignored since the change is so minor):

npm run swizzle @docusaurus/theme-classic BlogPostItem/Content -- --eject

Update the index.js file for the swizzled BlogPostItem/Content component to include the Footnotes component as follows:

/src/theme/BlogPostItem/Content/index.js
import React from 'react';
// ...
import { Footnotes } from 'react-a11y-footnotes';
// ...
export default function BlogPostItemContent({ children, className }) {
// ...
return (
<div
// ...
<MDXContent>
{children}
<Footnotes />
</MDXContent>
</div>
);
}

Styling

For the sake of completeness, my personal configuration for footnote styling includes the following options (largely from the CodeSandbox demo):

/src/css/custom.scss
/* begin react-a11y-footnotes styling */
[data-a11y-footnotes-footer] {
margin-top: 2em;
font-size: 80%;
}

/**
* Initialiazing a `footnotes` counter on the wrapper
*/
body {
counter-reset: footnotes;
}

/**
* Inline footnotes references
* 1. Increment the counter at each new reference
* 2. Reset link styles to make it appear like regular text
*/
[data-a11y-footnotes-ref] {
counter-increment: footnotes; /* 1 */
text-decoration: none; /* 2 */
color: inherit; /* 2 */
cursor: default; /* 2 */
outline: none; /* 2 */
}

/**
* Actual numbered references
* 1. Display the current state of the counter (e.g. `[1]`)
* 2. Align text as superscript
* 3. Make the number smaller (since it's superscript)
* 4. Slightly offset the number from the text
* 5. Reset link styles on the number to show it's usable
*/
[data-a11y-footnotes-ref]::after {
content: "[" counter(footnotes) "]"; /* 1 */
vertical-align: super; /* 2 */
font-size: 0.65em; /* 3 */
margin-left: 2px; /* 4 */
color: var(--ifm-link-color); /* 5 */
text-decoration: underline; /* 5 */
cursor: pointer; /* 5 */
}

/**
* Resetting the default focused styles on the number
*/
[data-a11y-footnotes-ref]:focus::after {
outline: thin dotted;
outline-offset: 2px;
}

[data-a11y-footnotes-back-link] {
font-size: 80%;
}
/* end react-a11y-footnotes styling */

Examples

Footnotes with identical IDs will not display correctly

From the package docs on ID generation for footnotes:

If no id is passed to references (<FootnoteRef>) — which is usually the case — the id will be computed from the content of the reference. For instance if the text says "CSS counters", the resolved identifiers will be css-counters-ref and css-counters-note.

Hence, if no id is passed for two footnotes that have identical contents, then the first footnote will be displayed correctly, but the second footnote will not show up, and it will also mess up the numbering for all subsequent footnotes. Try it yourself:

This <FootnoteRef description="First footnote with 'footnote' as its contents.">footnote</FootnoteRef>
will show just fine.

This <FootnoteRef description="Second footnote with 'footnote' as its contents.">footnote</FootnoteRef>
will not show at all; additionally, numbering will be messed up for subsequent footnotes.

This <FootnoteRef description="A different footnote.">differnent footnote</FootnoteRef>
would show up as the third footnote, but only two footnotes would be present.

Word to the wise: be sure such collisions are not possible by the unique nature of a footnote's contents or provide a unique id prop to the FootnoteRef component that you will then be responsible for tracking.

All examples below come from the examples in the package documentation (the source code input is shown, immediately followed by the output):

Example 1

Input
Maintaining <FootnoteRef description='Footnotes are notes placed at the bottom of a page. They cite references or comment on a designated part of the text above it.'>footnotes</FootnoteRef> manually can be a pain.

Maintaining footnotes manually can be a pain.

Example 2

Input
<FootnoteRef description='Cascading Style Sheets'>CSS</FootnoteRef> can be used to our advantage here.

CSS can be used to our advantage here.

Example 3

Input
It becomes easy to maintain footnotes *automatically* by using CSS <FootnoteRef id='with-a-custom-id' description={<> <a href='https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Lists_and_Counters/Using_CSS_counters' target='_blank' rel='noopener noreferrer'> CSS counters </a>are, in essence, variables maintained by CSS whose values may be incremented by CSS rules to track how many times they’re used.</>} >counters</FootnoteRef> to add the numbered references in the text and an ordered list to display the actual footnotes in the footer.

It becomes easy to maintain footnotes automatically by using CSS counters to add the numbered references in the text and an ordered list to display the actual footnotes in the footer.

Footnotes

  1. This is just the first footnote. More examples will follow. Click the icon on the far right to jump back to the main text. 
  2. Footnotes are notes placed at the bottom of a page. They cite references or comment on a designated part of the text above it. 
  3. Cascading Style Sheets 
  4. CSS counters are, in essence, variables maintained by CSS whose values may be incremented by CSS rules to track how many times they’re used.