Render Mermaid diagrams as accessible inline SVG during your Eleventy build. No client-side JavaScript required.
- Build-time rendering from Markdown
```mermaidfences - Inline SVG output in static HTML
- Accessible
<figure>wrapper with summary, caption, and description support - Customizable Mermaid themes and
themeVariablesfor brand colors - Font and CSS customization for branded typography
- Optional logo in the diagram wrapper
- Configurable strict or lenient error handling
- Browserless rendering via
isomorphic-mermaid(no Playwright/Chromium) - Works on Cloudflare Pages and other restricted CI environments
- Eleventy 3.x, TypeScript, ESM
- Node.js 18+
- Eleventy 3.x
npm install --save-dev eleventy-plugin-mermaid-build @11ty/eleventyNo browser or Playwright install step is required.
In eleventy.config.js:
import pluginMermaidBuild from "eleventy-plugin-mermaid-build";
export default function (eleventyConfig) {
eleventyConfig.addPlugin(pluginMermaidBuild, {
theme: "base",
fontFamily: "Inter, system-ui, sans-serif",
themeVariables: {
primaryColor: "#e8f4ff",
primaryTextColor: "#0b2e4a",
lineColor: "#1d6fb8",
},
logo: {
src: "/assets/logo.svg",
alt: "Acme Corp",
position: "top-right",
},
errorMode: "strict",
});
}In Markdown:
```mermaid
flowchart LR
Write["Write Markdown"] --> Build["Eleventy build"]
Build --> SVG["Inline SVG"]
```Diagrams can include optional YAML frontmatter for a caption title:
```mermaid
---
title: Checkout abandonment diagnostic
---
flowchart TB
SIGNAL["Strong add to cart<br/>Zero purchases"]
SIGNAL --> BUCKET{Where did checkout stop?}
```| Option | Type | Default | Description |
|---|---|---|---|
theme |
"default" | "dark" | "neutral" | "forest" | "base" |
"default" |
Built-in Mermaid theme. Use "base" with themeVariables for custom colors. |
themeVariables |
object |
— | Color and styling overrides. Requires theme: "base" for full customization. |
fontFamily |
string |
— | Diagram font family. |
fontSize |
string |
— | Diagram font size, e.g. "16px". |
css |
string | URL |
— | Local CSS file read at build time. Use for @font-face rules. See Custom fonts. |
logo |
LogoOptions |
— | Brand logo shown in the accessible wrapper. |
wrapperClass |
string |
"epmb-figure" |
Extra class on the outer <figure>. |
mermaidConfig |
MermaidConfig |
— | Full Mermaid config merged on top of theme settings. |
renderOptions |
object |
— | Extra renderer options (containerStyle, prefix). |
iconPacks |
IconPack[] |
— | Custom Mermaid icon packs. |
errorMode |
"strict" | "warn" |
"strict" |
Fail the build or warn and render an error placeholder. |
showCaption |
boolean |
true |
Show a <figcaption> when Mermaid provides a title. |
logo: {
src: "/assets/logo.svg", // Public site path or URL
alt: "Acme Corp", // Empty string for decorative logos
position: "top-right", // top-left | top-right | bottom-left | bottom-right
width: 48,
height: 48,
className: "my-logo",
}The logo appears in the accessible wrapper around the diagram, not inside the Mermaid canvas. This keeps branding separate from diagram content.
Use Mermaid's base theme with themeVariables:
eleventyConfig.addPlugin(pluginMermaidBuild, {
theme: "base",
themeVariables: {
primaryColor: "#fff4dd",
primaryTextColor: "#1a1a1a",
primaryBorderColor: "#ff9800",
lineColor: "#546e7a",
secondaryColor: "#f5f5f5",
tertiaryColor: "#eceff1",
},
});See the Mermaid theme variable docs for the full list.
Set fontFamily for diagram text, and optionally point css at a local CSS file with @font-face rules:
eleventyConfig.addPlugin(pluginMermaidBuild, {
theme: "base",
fontFamily: "Brand Sans, sans-serif",
css: "./src/css/mermaid-fonts.css",
});The css option reads a local file path at build time and injects it into the headless render environment. Remote http(s) URLs are not loaded during rendering. You still need to serve the font files and include the @font-face CSS on your site for visitors.
Any Mermaid configuration can be passed through:
mermaidConfig: {
securityLevel: "strict",
flowchart: {
htmlLabels: true,
curve: "basis",
},
sequence: {
diagramMarginX: 24,
},
},The plugin sets headless-safe defaults (startOnLoad: false) before merging your config. HTML labels are not supported in the svgdom render environment; <br/> tags in diagram labels are automatically converted to line breaks.
strict(default): invalid syntax fails the build with file path and sourcewarn: logs an accessible error placeholder and continues the build
Diagrams render inside an accessible figure:
<figure class="epmb-figure" role="figure" aria-labelledby="epmb-1-caption" aria-describedby="epmb-1-description">
<p class="epmb-figure__summary visually-hidden" id="epmb-1-summary">Flow</p>
<div class="epmb-figure__brand epmb-figure__brand--top-right">
<img class="epmb-figure__logo" src="/assets/logo.svg" alt="Acme Corp" />
</div>
<div class="epmb-figure__content">
<!-- inline SVG -->
</div>
<p class="epmb-figure__description visually-hidden" id="epmb-1-description">...</p>
<figcaption class="epmb-figure__caption" id="epmb-1-caption">Flow</figcaption>
</figure>Style the wrapper with the included BEM-style classes or your own wrapperClass.
npm install
npm run build
npm ci --prefix demo
npm run demo:build
npm run demo:serveOpen the served URL to preview rendered diagrams. No Playwright or browser install is needed.
npm install
npm test
npm run lint
npm run build- A Markdown-it fence rule converts
```mermaidblocks into build placeholders. - An Eleventy HTML transform finds placeholders in each output
.htmlfile. - Diagrams are rendered in batch via
isomorphic-mermaid(jsdom + svgdom, no browser). - Placeholders are replaced with accessible
<figure>markup containing inline SVG.
MIT