notes.dt.in.th

One feature I wish existed in most blog platforms are "interactive footnotes." They are like footnotes, but instead of jumping to the bottom of the page (disrupting the reading flow), the footnote contents appears in a popup1.

Some examples in the wild

Setting this up in VuePress

Note: This solution is hacky and not clean but it works well enough for me.

  1. Install the npm packages

    yarn add markdown-it-footnote littlefoot
  2. Add markdown-it-footnote to .vuepress/config.js

    // .vuepress/config.js
    module.exports = {
      // ...
      markdown: {
        extendMarkdown: (md) => {
          md.use(require('markdown-it-footnote'))
        },
      },
    }
  3. Add .vuepress/theme/utils/InteractiveFootnotes.js

    import 'littlefoot/dist/littlefoot.css'
    let latest
    
    export async function setupInteractiveFootnotes() {
      // littlefoot requires a DOM to initialize; it will crash when prerendering
      const { default: littlefoot } = await import('littlefoot/dist/littlefoot')
    
      if (latest) {
        latest.unmount()
      }
      latest = littlefoot()
    }
  4. Call setupInteractiveFootnotes in mounted and updated in the .vuepress/theme/components/Page.vue component.

    <template>
      <DefaultThemePage v-bind="$attrs"></DefaultThemePage>
    </template>
    
    <script>
    import DefaultThemePage from '@parent-theme/components/Page.vue'
    import { setupInteractiveFootnotes } from '../utils/InteractiveFootnotes'
    
    export default {
      components: { DefaultThemePage },
      mounted() {
        setupInteractiveFootnotes()
      },
      updated() {
        setupInteractiveFootnotes()
      },
    }
    </script>

Note when using with Prettier

The markdown-it-footnote plugin requires at least 4 spaces of indentation to parse multiline footnotes. However Prettier will reduce the indentation to 2 spaces, breaking it. As a workaround, use ignore comments to tell Prettier not to touch the footnotes.

<!-- prettier-ignore-start -->[^footnote]:    Paragraph 1    Paragraph 2<!-- prettier-ignore-end -->

Example implementation

This commit shows how I implemented littlefoot in my website https://dt.in.th/

Footnotes

  1. Like this.