Documentation and technical writing often require visual elements to communicate complex concepts effectively. Mermaid diagrams offer a powerful solution: write diagrams as code, render them as beautiful SVGs. This guide shows you how to integrate Mermaid into your Hugo workflow using partials, creating a seamless experience for both content creators and readers.

What is Mermaid?

Mermaid is a JavaScript-based diagramming tool that transforms simple text definitions into interactive diagrams. Instead of wrestling with traditional diagramming software, you write diagram syntax directly in your markdown:

flowchart TD A[Start] --> B{Decision} B -->|Yes| C[Action 1] B -->|No| D[Action 2] C --> E[End] D --> E

Key advantages:

  • Version Control Friendly: Diagrams are text, so they diff and merge like code
  • Maintainable: Easy to update and refactor diagram content
  • Consistent Styling: Automatic, professional appearance
  • Format Flexibility: Supports flowcharts, sequences, Gantt charts, and more

Mermaid Diagram Types

Mermaid supports various diagram types for different use cases:

Flowcharts

Perfect for process flows and decision trees:

flowchart LR A[Data Input] --> B[Processing] B --> C{Validation} C -->|Valid| D[Store Data] C -->|Invalid| E[Error Handling] D --> F[Success Response] E --> G[Error Response]

Sequence Diagrams

Ideal for API interactions and system communications:

sequenceDiagram participant U as User participant A as API Gateway participant S as Service participant D as Database U->>A: Request A->>S: Process S->>D: Query D-->>S: Result S-->>A: Response A-->>U: Final Result

Git Graphs

Excellent for development workflow documentation:

--- title: Example Git diagram --- gitGraph commit id: "Initial commit" branch feature checkout feature commit id: "Add feature" commit id: "Fix bug" checkout main commit id: "Update docs" merge feature commit id: "Release v1.0"

Hugo Integration Architecture

Integrating Mermaid into Hugo requires a strategic approach that balances performance, maintainability, and functionality:

flowchart TD A[Hugo Site] --> B[Theme Partials] B --> C[Mermaid Partial] C --> D[CDN Loading] C --> E[Local Assets] D --> F[Rendered Diagrams] E --> F G[Markdown Content] --> H[Mermaid Code Blocks] H --> I[HTML Processing] I --> F

The cleanest approach uses Hugo partials to conditionally load Mermaid resources.

Step 1: Create the Mermaid Detection Logic

Create layouts/_default/_markup/render-codeblock-mermaid.html to automatically detect Mermaid blocks:

<div class="mermaid">
    {{ .Inner | htmlEscape | safeHTML }}
</div>
{{ .Page.Store.Set "hasMermaid" true }}

Step 2: Add Mermaid Loading to Base Template

Add the following to your layouts/_default/baseof.html (or theme’s equivalent):

{{ 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,
    theme: 'base',
    themeVariables: {
        'primaryColor': '#567ebd',
        'primaryTextColor': '#ffffff',
        'primaryBorderColor': '#2b4c7e',
        'lineColor': '#2b4c7e',
        'secondaryColor': '#567ebd',
        'tertiaryColor': '#f0f4f8'
    }
  });
</script>

<!-- Optional: Custom Mermaid styling -->
<style>
.mermaid {
    text-align: center;
    margin: 2rem 0;
}

.mermaid svg {
    max-width: 100%;
    height: auto;
}

/* Dark mode compatibility */
@media (prefers-color-scheme: dark) {
    .mermaid {
        filter: invert(1) hue-rotate(180deg);
        background-color: transparent;
    }
}
</style>
{{- end -}}

Step 3: Configuration Options

Add Mermaid configuration to your config.yml:

params:
  mermaid:
    theme: "default"  # Options: default, dark, forest, neutral
    # Optional: Local asset path if not using CDN
    # localPath: "/js/mermaid.min.js"

Method 2: Code Block Integration (Standard Approach)

The most common and Hugo-native approach is using standard markdown code blocks with the mermaid language identifier. This works automatically with the render hook we created above:

Usage in markdown:

```mermaid
flowchart TD
    A[User Login] --> B{Credentials Valid?}
    B -->|Yes| C[Generate Token]
    B -->|No| D[Show Error]
    C --> E[Redirect to Dashboard]
```

This approach:

  • Works automatically with the render hook
  • Follows standard markdown conventions
  • Is supported across different static site generators
  • Requires no additional shortcode configuration

Advanced Configuration

Performance Optimization

<!-- layouts/partials/mermaid.html with performance enhancements -->
{{- if .Page.Store.Get "hasMermaid" -}}
<!-- Preload Mermaid for better performance -->
<link rel="preload" href="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js" as="script">

<script>
// Lazy load Mermaid when diagrams are in viewport
document.addEventListener('DOMContentLoaded', function() {
    const mermaidBlocks = document.querySelectorAll('.mermaid');
    
    if (mermaidBlocks.length === 0) return;
    
    // Intersection Observer for lazy loading
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting && !entry.target.dataset.processed) {
                initializeMermaid();
                entry.target.dataset.processed = 'true';
            }
        });
    }, { rootMargin: '50px' });
    
    mermaidBlocks.forEach(block => observer.observe(block));
    
    function initializeMermaid() {
        if (window.mermaid) {
            mermaid.init();
        } else {
            // Load Mermaid dynamically
            const script = document.createElement('script');
            script.src = 'https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js';
            script.onload = () => {
                mermaid.initialize({
                    startOnLoad: false,
                    theme: '{{ .Site.Params.mermaid.theme | default "default" }}'
                });
                mermaid.init();
            };
            document.head.appendChild(script);
        }
    }
});
</script>
{{- end -}}

Theme Integration

For better integration with your site’s design:

/* Custom Mermaid theming */
.mermaid-container {
    background: var(--background-color, #fff);
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
    padding: 1.5rem;
    margin: 2rem 0;
    overflow-x: auto;
}

.mermaid-caption {
    text-align: center;
    margin-top: 1rem;
    color: var(--text-muted, #64748b);
    font-size: 0.9rem;
}

/* Responsive diagrams */
@media (max-width: 768px) {
    .mermaid svg {
        transform: scale(0.8);
        transform-origin: top left;
    }
}

Security Considerations

When using Mermaid, consider these security aspects:

<!-- Content Security Policy friendly version -->
<script nonce="{{ .Hugo.CSPNonce }}">
// CSP-compliant initialization
document.addEventListener('DOMContentLoaded', function() {
    // Sanitize diagram content
    const mermaidElements = document.querySelectorAll('.mermaid');
    mermaidElements.forEach(element => {
        const content = element.textContent;
        // Basic content validation
        if (content.includes('<script') || content.includes('javascript:')) {
            element.innerHTML = '<p>⚠️ Diagram content blocked for security</p>';
            return;
        }
    });
    
    mermaid.initialize({
        securityLevel: 'strict',
        startOnLoad: true
    });
});
</script>

Local Asset Management

For production sites requiring strict asset control:

Step 1: Download Mermaid

# Download specific version
curl -o static/js/mermaid.min.js \
  https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js

Step 2: Update Partial

<!-- layouts/partials/mermaid.html with local assets -->
{{- if .Page.Store.Get "hasMermaid" -}}
<script src="{{ "js/mermaid.min.js" | relURL }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
    mermaid.initialize({
        startOnLoad: true,
        theme: '{{ .Site.Params.mermaid.theme | default "default" }}'
    });
});
</script>
{{- end -}}

Troubleshooting Common Issues

Diagrams Not Rendering

Check initialization:

// Debug version for troubleshooting
mermaid.initialize({
    startOnLoad: true,
    logLevel: 'debug',  // Add this for debugging
    theme: 'default'
});

Verify content detection:

<!-- Add debugging to render hook -->
{{- (.Page.Store.Set "hasMermaid" true) -}}
<!-- DEBUG: Mermaid block detected -->
<div class="mermaid">
{{- .Inner | safeHTML -}}
</div>

Content Security Policy Conflicts

<!-- CSP-friendly version -->
<script {{ with hugo.CSPNonce }}nonce="{{ . }}"{{ end }}>
// Your Mermaid initialization code
</script>

Mobile Responsiveness

/* Better mobile handling */
.mermaid {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.mermaid svg {
    min-width: 100%;
    max-width: none;
}

Real-World Examples

Documentation Workflow

flowchart TD A[Write Documentation] --> B[Include Mermaid Diagrams] B --> C[Hugo Build Process] C --> D[Partial Detection] D -->|Has Mermaid| E[Load Mermaid.js] D -->|No Mermaid| F[Skip Loading] E --> G[Render Diagrams] F --> H[Static HTML Only] G --> I[Final Site] H --> I

API Documentation

sequenceDiagram participant Client participant API participant Auth participant Database Client->>API: POST /api/login API->>Auth: Validate credentials Auth-->>API: Token generated API->>Database: Log session Database-->>API: Session stored API-->>Client: 200 OK + Token

Performance Monitoring

Track Mermaid’s impact on your site:

// Performance monitoring
const mermaidStart = performance.now();

mermaid.initialize({
    startOnLoad: true,
    theme: 'default'
});

mermaid.init().then(() => {
    const mermaidTime = performance.now() - mermaidStart;
    console.log(`Mermaid rendered in ${mermaidTime.toFixed(2)}ms`);
    
    // Optional: Send to analytics
    if (typeof gtag !== 'undefined') {
        gtag('event', 'mermaid_render', {
            'render_time': Math.round(mermaidTime),
            'diagram_count': document.querySelectorAll('.mermaid').length
        });
    }
});

Deployment Considerations

Build Process Integration

# GitHub Actions example
name: Build and Deploy Hugo Site
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
          extended: true
      
      - name: Build site
        run: |
          hugo --minify
          # Verify Mermaid integration
          grep -r "mermaid" public/ || echo "No Mermaid diagrams found"          
      
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

Content Validation

#!/bin/bash
# validate-mermaid.sh - Check for valid Mermaid syntax

echo "Validating Mermaid diagrams..."

# Find all Mermaid code blocks
find content -name "*.md" -exec grep -l "```mermaid" {} \; | while read file; do
    echo "Checking $file..."
    
    # Extract Mermaid blocks and validate syntax
    awk '/```mermaid/,/```/' "$file" | grep -v '```' | \
    while IFS= read -r line; do
        if [[ -n "$line" ]]; then
            # Basic syntax validation
            if [[ "$line" =~ ^[[:space:]]*$ ]]; then
                continue
            fi
            echo "  Diagram line: $line"
        fi
    done
done

echo "Mermaid validation complete."

Conclusion

Integrating Mermaid into Hugo using partials provides a clean, maintainable solution for adding diagrams to your static site. The key benefits of this approach:

  1. Performance: Only loads Mermaid when needed
  2. Maintainability: Centralized configuration through partials
  3. Flexibility: Support for various diagram types and customization
  4. SEO-Friendly: Diagrams render as searchable SVG content

Best Practices Summary:

  • Use auto-detection through render hooks for seamless integration
  • Implement lazy loading for better performance
  • Consider local asset hosting for production environments
  • Add proper error handling and CSP compliance
  • Monitor performance impact with analytics

This approach has proven effective for technical documentation, research publications, and any content requiring visual process representation. The combination of Hugo’s build speed and Mermaid’s diagram capabilities creates a powerful documentation platform.

© 2025 Seyed Yahya Shirazi. All rights reserved.