Markdown Render Hooks In Hugo

28 December, 2022

Recently i was fiddling with my blog theme, and wanted to see what it would look like if the headings were in uppercase.

I came up with 3 different solutions on how to accomplish this, one of which uses Hugo’s Markdown render hooks.

A bad way to do it

My first (intrusive) thought was to rewrite all Markdown headings to uppercase using sed.

This command matches all lines starting with one to five pound signs, and replaces them with uppercase versions of themselves:

$ sed -i -E 's/^([#]{1,5}.*)$/\U\1/' content/blog/*.md

However, this approach would not only mangle the original titles in the source code, but also requires me to keep writing all headings in uppercase.

Representation should be decoupled from content.

A better way to do it

This site is powered by a static site generator Hugo.

Hugo’s default Markdown renderer (Goldmark) supports Markdown render hooks, which can be used to override certain parts of the default Markdown rendering.

This is done by creating templates with a particular naming scheme in layouts/_default/_markup.

I modified the default renderer to use Hugo’s upper function to turn heading text to uppercase, and added a decorative rectangle for some visual flare:

<!╌ layouts/_default/_markup/render-heading ╌>
<h{{ .Level }}>{{ upper .Text | safeHTML }}</h{{ .Level }}>
{{ $decoLevels := (slice 1 2) }}
{{ if ( in $decoLevels .Level ) }}
  <div class="header-rect"></div>
{{ end }}

It’s worth noting that this template only modifies the Markdown renderer, so HTML layouts will not inherit these changes!

If you want to extend this logic to the HTML layouts, use a partial:

{{ partial "header.html" (dict "Level" 1 "Text" "Header text here!") }}

The best way to do it?

If the only thing i wanted to do was to turn header text uppercase, then arguably the easiest way would have been to just use CCS:

text-transform: uppercase;