Writing collapsible inline footnotes in Hugo with Markdown
I use Hugo as the static site builder for my blog. I love it because it’s fast (blisteringly fast) and for the most part it just gets out of the way.
However, Hugo’s support for customising the rendering of Markdown into HTML is … lacking, to say the least. Hugo uses Goldmark under the hood, which supports Extensions, but Hugo doesn’t natively plug in to those. I’d previously been using a Hugo shortcode to wrap around some arbitrary Markdown and convert it into a footnote HTML:
<label for="fn{{ .Get "id" }}">{{ .Get "label" }}</label>
<input type="checkbox" id="fn{{ .Get "id" }}" />
<small id="fn{{ .Get "id" }}">
{{ .Inner | markdownify }}
</small>
But using it in Markdown means writing something inordinately verbose and clunky like:
This is some text,{{< footnote id="1" label="footnote!" >}}and here's some **markdown** in a footnote{{< /footnote >}}
I considered switching to pandoc for my Markdown preprocessing, but that would mean changing my whole build system and using GitHub Actions with a pandoc
workflow instead of the (super quick) Cloudflare Pages Hugo runner. I did some browsing and realised that I was not the only one thinking deeply about footnotes and sidenotes in Hugo.
I’ve been struggling with this for a while, but I realised that Hugo supports render hooks for select Markdown elements. Unfortunately, footnotes are not included, but images are! In Markdown, the standard syntax for images looks like: 
, which is not too dissimilar to the footnote syntax [^label]: footnote
. So I built a little layouts/_markup/render-image.html
hook:
{{- if eq .Destination "fn" -}}
{{- /* This is a footnote using image syntax */ -}}
{{- $label := .PlainText | default "note" -}}
{{- $content := .Title | default "Footnote content" -}}
{{- $id := .Ordinal -}}
<label for="fn{{ $id }}" class="footnote-trigger">{{ $label }}</label><input type="checkbox" id="fn{{ $id }}" class="footnote-checkbox" /><small class="footnote-aside" id="fn{{ $id }}">{{ $content | markdownify }}</small>
{{- else -}}
{{- /* This is a regular image */ -}}
<img src="{{ .Destination | safeURL }}"
{{- with .PlainText }} alt="{{ . }}"{{ end -}}
{{- with .Title }} title="{{ . }}"{{ end -}}
>
{{- end -}}
so that I can write:

and, with some pure CSS magic, have it render into a collapsible inline footnote! You can see it live on my website now: I’ve started using it to add maths proofs and asides as footnotes that expand inline on hover.