Mermaid diagrams in Astro 7
By Shank
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"→ Mermaiddefaultdata-theme="dark"→ Mermaiddark
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.