Plugins
Mermaid
/plugin-mermaid renders fenced ```mermaid code blocks to inline SVG at build time using mermaid-isomorphic. No Mermaid JavaScript is shipped to the browser — the SVG is embedded directly in the HTML output.
Installation
pnpm add /plugin-mermaid
Note:
mermaid-isomorphicuses Playwright internally to render diagrams in a headless Chromium browser. On first install, Playwright will download a Chromium binary (~150 MB). This can be slow on CI — see Performance below.
Basic setup
// stedefast.config.ts
import { defineConfig } from "@stedefast/core";
import { MermaidPlugin } from "/plugin-mermaid";
export default defineConfig({
// ...
plugins: [
MermaidPlugin({ theme: "default" }),
],
});
Any fenced ```mermaid block in your Markdown will be rendered to an inline SVG:
```mermaid
flowchart LR
A[Start] --> B{Decision}
B -->|Yes| C[Continue]
B -->|No| D[Stop]
```
The output is wrapped in a <figure class="sf-diagram"> element.
Supported diagram types
All Mermaid diagram types are supported. A few examples:
Flowchart
```mermaid
flowchart TD
A[User] --> B[Browser]
B --> C[CDN]
C --> D[Origin]
```
Sequence diagram
```mermaid
sequenceDiagram
participant Browser
participant Worker
Browser->>Worker: POST /submit
Worker-->>Browser: 200 OK
```
Class diagram
```mermaid
classDiagram
class StedefastPlugin {
+name: string
+rehypePlugins: PluggableList
+headAssets: HeadAssets
}
```
State diagram
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> Building: build()
Building --> Done: success
Building --> Error: failure
Done --> [*]
```
ER diagram
```mermaid
erDiagram
POST ||--o{ COMMENT : has
POST {
string slug
string title
}
COMMENT {
string body
string author
}
```
Gantt chart
```mermaid
gantt
title Project Timeline
section Phase 1
Research :a1, 2026-01-01, 14d
Design :a2, after a1, 7d
section Phase 2
Build :a3, after a2, 21d
```
Pie chart
```mermaid
pie title Traffic Sources
"Organic" : 60
"Direct" : 25
"Referral" : 15
```
Themes
Mermaid ships four built-in themes:
| Theme | Description |
|---|---|
default |
Light, neutral colour palette |
dark |
Dark background variant |
neutral |
Monochrome, minimal |
forest |
Green-tinted |
Pass theme to select one:
MermaidPlugin({ theme: "neutral" })
Dual light/dark themes
For sites with light and dark colour modes, use themes to render two SVGs and swap them via CSS:
MermaidPlugin({
themes: {
light: "default",
dark: "dark",
},
})
The plugin renders both SVGs and emits:
<figure class="sf-diagram">
<span class="sf-diagram-light"><!-- light SVG --></span>
<span class="sf-diagram-dark"><!-- dark SVG --></span>
</figure>
It also automatically injects the following CSS into every page <head>:
.sf-diagram-dark { display: none; }
@media (prefers-color-scheme: dark) {
.sf-diagram-light { display: none; }
.sf-diagram-dark { display: block; }
}
If your theme uses a manual dark mode class (e.g. .dark on <html>), add this to your theme/styles/global.css instead:
.sf-diagram-dark { display: none; }
.dark .sf-diagram-light { display: none; }
.dark .sf-diagram-dark { display: block; }
Options reference
| Option | Type | Default | Description |
|---|---|---|---|
theme |
string |
"default" |
Mermaid theme for single-theme mode. One of "default", "dark", "neutral", "forest". Mutually exclusive with themes. |
themes |
{ light: string; dark: string } |
— | Dual theme mode — renders two SVGs and swaps on prefers-color-scheme. Mutually exclusive with theme. |
backgroundColor |
string |
"transparent" |
Background colour applied to rendered SVGs via Mermaid's themeVariables. |
Error handling
If a diagram fails to render (invalid syntax, unsupported diagram type), the plugin logs a warning to stderr and leaves the original <pre><code class="language-mermaid"> block in place. The build continues without failing.
Performance
The first build will be slow because mermaid-isomorphic launches a Chromium process via Playwright. Subsequent diagrams in the same build are faster — the browser instance is reused across all diagrams on the page.
Identical diagrams (same source text and theme) are cached in memory within a single build invocation to avoid redundant renders.
CI caching: To avoid re-downloading Chromium on every CI run, cache the Playwright browser cache directory. For GitHub Actions:
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}