No results

For AI agents and crawlers: a structured index of this site is available at https://danny.is/llms.txt.

Theme-aware Mermaid Diagrams at build-time

I mentioned a satteriMermaid plugin in my note on Upgrading to Astro 7 and switching to Sätteri and wanna expand on that briefly because this site now supports themed mermaid diagrams!

Six example Mermaid diagrams – a flowchart, sequence diagram, state diagram, pie chart, class diagram and Gantt chart – rendered in this site’s light theme
Example mermaid diagrams in light mode
The same six Mermaid diagrams rendered in this site’s dark theme
Example mermaid diagrams in dark mode

Mermaid is a way to describe diagrams in plain text and have them rendered nicely. Inside markdown files the mermaid code is usually written inside a fenced code block like this.

```mermaid
graph TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug]
D --> B
```

Which is rendered like this.

Yes

No

Start

Is it working?

Great!

Debug

In statically-generated sites we’ve a few options for handling mermaid code: we can render them using a client-side JS library, we can generate raster images at build-time, or we can generate SVGs at build time and embed them in our HTML. My preference is for the last, which is easy enough using one of the many mermaid libraries.

I first added support for this ages ago but didn’t really give it much thought and only supported one colour scheme.

Mermaid theme variables are configured in mermaid.js like this:

export const mermaidConfig = {
theme: 'base',
themeVariables: {
primaryColor: '#d9745b',
primaryTextColor: '#1a1d20',
primaryBorderColor: '#d9745b',
}
}

Whereas this site’s theming relies on global CSS variables which are already theme-aware. Anything using --color-coral just works when the theme changes because:

--color-coral: light-dark(#fa6863, #ff9890);

But we can’t use CSS variables in mermaid.js, hence the need for that satteriMermaid plugin I mentioned. It uses mermaid-isomorphic to build the SVGs using the hex colours defined in mermaid.js and then rewrites the syntax tree to replace them with CSS variables.

The --mermaid-* CSS variables are defined in _mermaid.css and map one-to-one onto the colour variables defined in mermaid.js except the CSS colours are defined using light-dark() like this:

/* ... */
--mermaid-text: var(--color-text);
--mermaid-background: light-dark(var(--color-white), var(--color-background-secondary));
--mermaid-label-background: oklch(from var(--color-background-secondary) l c h / 60%);
--mermaid-coral: var(--color-coral);
--mermaid-purple: var(--color-purple);
--mermaid-green: var(--color-green);
--mermaid-note-background: light-dark(
oklch(97% 0.04 var(--hue-yellow)),
oklch(32% 0.05 var(--hue-yellow))
);
/* ... */

The end result is that mermaid code blocks in my markdown & MDX files are transformed into inline SVGs in the generated HTML and respond to theme changes because they use theme-aware CSS variables.