Diagrams in Hugo with Mermaid

blog
Published

September 23, 2020

Being able to write simple diagrams with text is very convenient. We can do this in Hugo by rendering with mermaid.js.

In particular I want to render some factor tree diagrams of the style of The Art of Insight. Like this one:

Factor tree

The final result looks like:

graph LR;
   A[sheets ream<sup>-1</sup> <br> 500] -->|-1| B[thickness <br> 10<sup>-2</sup>cm <br>] 
   C[thickness ream<sup>-1</sup> <br> 5cm] --> B
   B --> D[volume <br> 1cm<sup>3</sup>]
   E[height <br> 6cm] --> D
   F[width <br> 15cm] --> D

Implementation

I copied the Mermaid Hugo shortcode from the learn theme and put it in layouts/shortcodes/mermaid.html.

{{ $_hugo_config := `{ "version": 1 }` }}
<div class="mermaid" align="{{ if .Get "align" }}{{ .Get "align" }}{{ else }}center{{ end }}">{{ safeHTML .Inner }}</div>

Then following the mermaid documentation I inject the script into a template. For the hugo-casper3 theme I do this by making a copy of layouts/partials/site-header.html and adding the script to the top of the template.

<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>mermaid.initialize({ startOnLoad: true, securityLevel: 'loose'}});</script>

Then I can just include a diagram in any markdown document by putting the following between <mermaid> tags in handlebars.

graph LR;
   A[sheets ream<sup>-1</sup> <br> 500] -->|-1| B[thickness <br> 10<sup>-2</sup>cm <br>] 
   C[thickness ream<sup>-1</sup> <br> 5cm] --> B
   B --> D[volume <br> 1cm<sup>3</sup>]
   E[height <br> 6cm] --> D
   F[width <br> 15cm] --> D

Discussion

Ideally I would use Hugo to prerender the diagrams but unfortunately it’s not possible at this stage. I could use Blogdown to generate the diagrams with R, but I don’t want to have to write all my posts in RMarkdown. So instead we have to use client side rendering of diagrams, and R Markdown is a good example of this.

I found the solution with Mermaid in Julian Knight’s article about Embedding diagrams in a Hugo Page, and saw the implementation in Learn theme.

Note that the securityLevel: 'loose' configuration above allows representing HTML inside the diagram.

It would be better for stability to host the Mermaid files locally, rather than using the CDN above. For rendering speed it would be better in the footer than the header. But as a quick hack this seems to work well enough.