Mermaid diagrams in Astro 7

By Shank

Mermaid diagrams in Astro 7

Exporting images every time a design diagram changes is not a ideal workflow. This site is Astro 7, static, markdown content collections, class-based dark mode. I wanted a mermaid fence in the markdown and a diagram on the page.

That is what this post is. The diagrams below are live.

Using astro-mermaid

npm install astro-mermaid mermaid

astro-mermaid is the integration. mermaid is a peer dependency. This page is on astro-mermaid 2.1 and Mermaid 11.

On Astro 7 you do not pin markdown.processor. Sätteri is already the default, and astro-mermaid 2.1 hooks in as a Sätteri mdast plugin. If you previously set processor: unified() just to keep diagrams working after the upgrade, you can drop that.

Put mermaid() first in integrations, before mdx():

import mermaid from 'astro-mermaid';

export default defineConfig({
  markdown: {
    syntaxHighlight: {
      type: 'shiki',
      excludeLangs: ['mermaid', 'math'],
    },
  },
  integrations: [
    mermaid({
      theme: 'neutral',
      autoTheme: true,
      enableLog: false,
    }),
    mdx(),
    sitemap(),
  ],
});

excludeLangs: ['mermaid'] keeps Shiki from treating a diagram fence as a code block. autoTheme is the useful one. More on that in a second.

Then you just write a fence:

```mermaid
flowchart LR
    A[Markdown] --> B[pre.mermaid]
    B --> C[SVG in the browser]
```

How it actually renders

Nothing gets drawn at build time. The integration turns the fence into a pre.mermaid block with the source still inside. On the client, mermaid.js loads only on pages that have one of those blocks, then replaces it with SVG.

flowchart LR
    A[Markdown fence] --> B[astro-mermaid plugin]
    B --> C["pre.mermaid"]
    C --> D[mermaid.js]
    D --> E[SVG]

Pages without a diagram do not load mermaid.js. That is why I did not bother with a build-time renderer for a static blog.

Dark mode

This site’s Tailwind dark mode is html.dark. astro-mermaid does not look at that class. autoTheme watches data-theme on <html> (or <body>):

  • data-theme="light" → Mermaid default
  • data-theme="dark" → Mermaid dark

If you only toggle .dark, the page theme flips and the diagrams stay on the old palette. I set both in the small head script (so it happens before first paint) and again on the toggle:

root.classList.toggle('dark');
root.setAttribute('data-theme', isDark ? 'dark' : 'light');

Toggle the sun/moon in the header and this one should re-render with it:

sequenceDiagram
    actor You
    participant Toggle as Theme toggle
    participant Html as html
    participant Mermaid as mermaid.js
    You->>Toggle: click
    Toggle->>Html: class dark plus data-theme
    Html->>Mermaid: MutationObserver
    Mermaid->>Mermaid: re-render the SVGs

That is the whole setup this site is running.