Introduction
This blog is managed with the workflow shown below.
graph LR org-mode -- <a href="https://ox-hugo.scripter.co/">ox-hugo</a> --> markdown -- <a href="https://gohugo.io/">Hugo</a> --> HTML
When you want to include a diagram like the flowchart above, what methods come to mind?
Surely, you’re not thinking about making diagrams in PowerPoint or similar tools, exporting them as images, and… calling it a day?
That’s a D-tier move

Figure 1: PowerPoint is truly D-tier
Putting that aside, since I wasn’t very knowledgeable about ways to make diagrams—especially when using ox-hugo—I asked Gemini 2.5 Pro to do a deep research on the topic. As a result, we created the following Tier List together. 1
As shown in the table, my personal recommendation is to use mermaid.js. However, the setup isn’t all that straightforward and can be a bit of a hassle, so I’m writing down the steps here.
Two Methods to Use mermaid.js
flowchart TD B{Are you a Mermadian?} -- Yes --> C{Want to render in the browser?} B -- No --> D[<a href="https://www.microsoft.com/ja-jp/microsoft-365/powerpoint">That's D-tier</a>] C -- Yes --> E[<a href="#方法2-hugoのレンダーフックでmermaid-dot-jsを使う">Method 2</a>] C -- No --> F[<a href="#方法1-org-babel-でpng-svgを生成">Method 1</a>]
Method 1: Use org-babel to Generate png/svg
Preparation
- Install mermaid-cli
- Install ob-mermaid in Emacs and configure it as explained in their README.
Usage
By executing mermaid code in an org-babel block like the example below, the generated image file will be inserted into your hugo content.
Source (org-mode)
#+begin_src mermaid :file ./images-in-content/mermaid-sample.svg :results file :exports results
graph LR;
A--> B & C & D
B--> A & E
C--> A & E
D--> A & E
E--> B & C & D
#+end_src
#+RESULTS:
[[file:./images-in-content/mermaid-sample.svg]]
Output (hugo)
Method 2: Use Hugo Render Hooks to enable mermaid.js
In Method 2, you use Hugo’s render hooks to directly render mermaid.js diagrams on the browser. The main advantage of this method is that you don’t need to generate image files—just write the code to display the diagram.
Preparation
- Following the official Hugo documentation, create
layouts/_markup/render-codeblock-mermaid.html
and add:<pre class="mermaid"> {{ .Inner | htmlEscape | safeHTML }} </pre>
- Add the following to
layouts/partials/extend_head.html
:If you want to prevent your site from breaking due to future library changes, you can specify the version in the URL, for example:{{ if .Store.Get "hasMermaid" }} <script type="module"> import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs'; mermaid.initialize({ startOnLoad: true }); </script> {{ end }}
'https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.esm.min.mjs'
.
Usage
Source (org-mode)
#+begin_src mermaid :exports code
graph LR;
A--> B & C & D
B--> A & E
C--> A & E
D--> A & E
E--> B & C & D
#+end_src
Output (hugo)
graph LR; A--> B & C & D B--> A & E C--> A & E D--> A & E E--> B & C & D
Personally, I recommend Method 2 for three main reasons:
- No local files are generated
- The diagram’s theme can be matched to hugo’s (for how, refer to the supplement below)
- You can use hyperlinks and other extended features of HTML
(Supplements)
(Supplement 1) Methods That Didn’t Work
As described in the ox-hugo documentation,
#+begin_mermaid
flowchart TD
Start --> Stop
#+end_mermaid
If you write it like this, ox-hugo converts it to markdown as:
<div class="mermaid">
flowchart TD
Start --> Stop
</div>
This isn’t the code fence I was expecting.
As a result, HTML like the following is produced, and you get a Syntax error in text
:
<div class="mermaid"></p><p>flowchart TDA –> B{Is it working?}B – Yes –> C[Great!]B – No –> D[Check Console]</p></div>
I didn’t pursue #+begin_mermaid
any further, but if someone else managed to make it work, I’d love to hear about it.
(Supplement 2) Centering mermaid Diagrams
By default, diagrams are left-aligned, so I add the following CSS to center them:
#+begin_export hugo
<style>
.mermaid {
text-align: center;
}
</style>
#+end_export
(Supplement 3) Switch mermaid.js Themes for Light/Dark Mode
By updating the script in layouts/partials/extend_head.html
as follows, you can change the default mermaid.js theme according to light or dark mode:
{{ if .Store.Get "hasMermaid" }}
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
function updateMermaidTheme() {
let mermaidTheme = 'default';
if (localStorage.getItem("pref-theme") === "dark" ||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches &&
!localStorage.getItem("pref-theme"))) {
mermaidTheme = 'dark';
}
mermaid.initialize({
startOnLoad: true,
theme: mermaidTheme
});
}
updateMermaidTheme();
</script>
{{ end }}
Conclusion
In this article, I explained two methods to use mermaid.js with ox-hugo.
Both methods let you embed diagrams in your ox-hugo content, but I personally recommend using the render hook approach.
That’s all for how to use mermaid.js with ox-hugo!
-
To be honest, Gemini 2.5 Pro rated “Hugo Kroki” as S-tier and “mermaid.js” as A-tier, but that makes no sense to me—so I swapped them. ↩︎