How to Render Mermaid Diagrams as SVG (and Stop Looking Like Every Other README)
A practical guide to rendering Mermaid as SVG — from the official CLI to custom themes, font fixes, dark mode, and when to stop fighting the defaults.
TL;DR Mermaid renders to SVG natively — but the default output usually isn't what you want in a README, slide, or doc. This post walks through the official
mmdcCLI, the four theming knobs that actually matter, the three rendering pitfalls everyone hits (fonts, viewBox, dark mode), and how to decide when DIY stops being worth your time. There's a live editor at the end if you want to skip ahead.
The problem nobody talks about
Mermaid is the de-facto "diagrams as code" choice in 2026 — GitHub, Notion, Obsidian, Docusaurus, GitLab, every static site generator worth its salt renders it natively.
That's the good news.
The bad news: 95% of Mermaid diagrams in the wild look exactly the same. Pastel pinks and blues, Comic-Sans-adjacent fonts, edges crossing nodes, arrowheads that don't quite point at anything. You've seen them. You've probably shipped some.
It's not a Mermaid problem — it's a defaults problem. The renderer is optimized for "something showed up", not "this is presentable".
Why SVG and not PNG
| Property | SVG | PNG |
|---|---|---|
| Scales without blur | ✅ | ❌ |
| Accessible (text selectable) | ✅ | ❌ |
Adapts to dark mode (currentColor) | ✅ | ❌ |
| Searchable in your repo | ✅ | ❌ |
Approach 1: The official Mermaid CLI
# Run without installing
npx @mermaid-js/mermaid-cli -i diagram.mmd -o diagram.svg
# Or install globally
npm install -g @mermaid-js/mermaid-cli
mmdc -i diagram.mmd -o diagram.svgThe four theming knobs that actually matter
1. theme (the cheapest win)
Built-in themes: default, forest, dark, neutral, base. Pick base if you want to customize from scratch.
2. themeVariables
Six variables actually matter: primaryColor, primaryTextColor, primaryBorderColor, lineColor, fontFamily, fontSize. Set those well, ignore the other 50.
3. Edge curves
Change edge curves from the default to linear or step. The default basis everywhere is one of the top reasons README diagrams look amateur.
4. Layout direction
Pick based on reading flow. LR for pipelines, TD for hierarchies.
Three rendering pitfalls
Fonts don't render in the saved SVG
Use a system font stack: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif.
viewBox cropping
Post-process to add padding:
function padViewBox(svgString, padding = 16) {
return svgString.replace(
/viewBox="(-?\d+\.?\d*) (-?\d+\.?\d*) (\d+\.?\d*) (\d+\.?\d*)"/,
(_, x, y, w, h) => {
const nx = parseFloat(x) - padding;
const ny = parseFloat(y) - padding;
const nw = parseFloat(w) + padding * 2;
const nh = parseFloat(h) + padding * 2;
return `viewBox="${nx} ${ny} ${nw} ${nh}"`;
}
);
}Dark mode is hardcoded
Replace fixed colors with currentColor:
function makeAdaptive(svgString) {
return svgString
.replace(/stroke="#[0-9a-fA-F]{6}"/g, 'stroke="currentColor"')
.replace(/fill="#[0-9a-fA-F]{6}"/g, 'fill="currentColor"');
}When DIY stops being worth the time
Three signals:
- You're maintaining a "diagram theme" file across multiple repos.
- You want to embed live diagrams in Notion / Linear / non-Markdown surfaces.
- Your inputs aren't just Mermaid — PlantUML, draw.io, AI prompts.
Beauty Diagram renders Mermaid, PlantUML, and draw.io to presentation-ready SVG. Free editor + CLI. (Disclosure: I work on it.)
Try the editor →# Render and save
npx @beauty-diagram/cli beautify flow.mmd --theme modern --out flow.svg
# Render and get a public share URL with an OG preview
npx @beauty-diagram/cli share flow.mmd --title "Auth flow"Wrap-up
Mermaid's defaults aren't bad — they're designed for "the diagram exists" rather than "the diagram is finished". Apply the checklist above and your README diagrams will look genuinely good.
If this was useful, drop a ❤️ on Dev.to and follow — I'm posting weekly on diagrams, docs, and developer ergonomics.