Adding Mermaid Diagrams to Hugo Sites

When writing technical documentation or blog posts, visual diagrams can significantly enhance content clarity.

Mermaid is a popular JavaScript library that renders diagrams and flowcharts from simple text definitions, making it perfect for markdown-based Hugo sites.

Mermaid allows you to create various diagram types using simple syntax:

  • Flowcharts and process diagrams
  • Sequence diagrams for system interactions
  • Gantt charts for project timelines
  • Git branch diagrams
  • Entity relationship diagrams

The Problem with Existing Tutorials

A quick web search reveals 4-5 tutorials on integrating Mermaid with Hugo. However, none worked out of the box for me across different Hugo themes. Common issues include:

  • Auto-detection methods that fail to find code blocks
  • Theme-specific implementations that break with updates
  • Loading Mermaid on every page regardless of need
  • Incompatibility with Hugo’s goldmark renderer

This article presents a working method that I use to enable Mermaid across themes, keeping things simple yet efficient when it comes to page loading.

The Working Solution

Step 1: Enable Unsafe HTML Rendering

First, ensure Hugo can render the JavaScript properly by adding this to your config.yaml:

markup:
  goldmark:
    renderer:
      unsafe: true

Or in config.toml:

[markup]
  [markup.goldmark]
    [markup.goldmark.renderer]
      unsafe = true

Step 2: Create the Mermaid Partial

Create layouts/partials/mermaid.html:

{{ if .Params.mermaid }}
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
  document.addEventListener('DOMContentLoaded', function() {
    // Look for mermaid code blocks
    const mermaidBlocks = document.querySelectorAll('pre code.language-mermaid');
    if (mermaidBlocks.length > 0) {
      mermaid.initialize({
        startOnLoad: false,
        theme: 'default',
        flowchart: {
          useMaxWidth: true
        }
      });
      
      mermaidBlocks.forEach((block, index) => {
        const graphDefinition = block.textContent;
        const div = document.createElement('div');
        div.className = 'mermaid';
        div.innerHTML = graphDefinition;
        block.parentNode.parentNode.replaceChild(div, block.parentNode);
      });
      
      mermaid.init();
    }
  });
</script>
{{ end }}

Step 3: Include the Partial in Your Base Template

Add the following to your layouts/_default/baseof.html just before the closing </body> tag:

<!DOCTYPE html>
<html lang="{{ with .Site.LanguageCode }}{{ . }}{{ else }}en-US{{ end }}">
{{- partial "head.html" . -}}

<body>
	{{- partial "preloader.html" . -}}
	{{- partial "header.html" . -}}
	{{- block "main" . }}{{- end }}
	{{- partial "footer.html" . -}}
	
	{{ partial "mermaid.html" . }}
</body>

</html>

Step 4: Usage in Content

To use Mermaid diagrams, simply add mermaid: true to your front matter:

---
title: "My Technical Post"
date: 2025-05-04T14:30:00+08:00
mermaid: true
---

# System Architecture

Here's our deployment flow:

```mermaid
graph TD
    A[Developer] -->|Push Code| B[GitHub]
    B -->|Webhook| C[Cloudflare Pages]
    C -->|Build| D[Hugo Site]
    D -->|Deploy| E[Production]
    
    style A fill:#e1f5fe
    style E fill:#c8e6c9

And a sequence diagram:

sequenceDiagram participant U as User participant B as Browser participant S as Server U->>B: Opens webpage B->>S: HTTP Request S->>B: HTML Response B->>U: Rendered page

Performance Benefits

By using front matter control (mermaid: true), you ensure:

  • Mermaid JavaScript only loads when needed
  • Faster page loads for content without diagrams
  • Clear indication of which pages use diagrams
  • No impact on SEO or Core Web Vitals for diagram-free pages

Example Diagrams

Here’s what you can create:

graph LR A[Start] --> B{Decision} B -->|Yes| C[Process A] B -->|No| D[Process B] C --> E[End] D --> E

This approach has served me well across multiple Hugo themes and projects.

Hope this helps!