Diagrams
Verto renders three diagram languages out of the box — Mermaid for flowcharts and sequence / state diagrams, Excalidraw for hand-drawn sketches, and D2 for declarative diagrams. All three share the same model, so once you've learned one you've learned them all.
| Renderer | Fence language | MDX component | Bundle | Best for |
|---|---|---|---|---|
| Mermaid | mermaid | <Mermaid> | ~1 MB | Flowcharts, sequence, state |
| Excalidraw | excalidraw | <Excalidraw> | dynamic | Hand-drawn sketches |
| D2 | d2 | <D2> | ~3 MB (WASM) | Declarative diagrams |
Two equivalent forms
Every renderer accepts your diagram in either of two forms:
- As a fenced code block — the familiar Markdown / Notion / GitHub form.
A
rehype-*plugin intercepts the block before Shiki sees it and routes it to a client-side renderer. - As an MDX component — for when you want to mix props, conditionals, or data binding into the source.
Both produce identical output. Reach for the fence for portability (it degrades to a labelled code block on GitHub), or the component when you're generating the diagram programmatically.
Every diagram bundle is dynamic-imported, so pages without diagrams pay zero bundle cost — and every renderer re-renders automatically when the reader toggles light / dark mode.
Mermaid
Verto supports Mermaid diagrams in two equivalent forms.
As a fenced code block
The familiar Markdown / Notion / GitHub form. A rehype-mermaid plugin
intercepts these blocks before Shiki sees them and routes them to a
client-side renderer.
As an MDX component
For when you want to mix props, conditionals, or data binding into the source:
State diagram
Theming
Diagrams use a Verto-branded palette built on Mermaid's base theme: nodes
pick up the site's accent blue, with mint and amber tints separating secondary
and tertiary tiers (e.g. nested states, sequence actor labels). Notes use a
soft yellow. Both light and dark modes are tuned to the same --accent-blue /
--text tokens used elsewhere on the site, so diagrams sit naturally inside
surrounding prose.
Excalidraw
Verto supports Excalidraw scenes in two equivalent forms.
As a fenced code block
The familiar Markdown / Notion / GitHub form. A rehype-excalidraw plugin
intercepts these blocks before Shiki sees them and routes them to a
client-side renderer that exports the scene to an inline read-only SVG.
The body of the fence is the JSON exported from Excalidraw (File → Export
image → SVG, or "Save to…" → .excalidraw). Either the full .excalidraw
payload or a bare { "elements": [...], "appState": {...}, "files": {...} }
triple works.
As an MDX component
For when you want to mix props or build the JSON dynamically:
Preview
A richer scene — three nodes connected by arrows, in classic Excalidraw hand-drawn style. The block below is rendered to an inline SVG at build / load time; you are looking at the actual output, not a screenshot.
Theming
The renderer passes Excalidraw's own theme: "light" | "dark" plus
exportWithDarkMode flag based on the active site theme, so diagrams sit
naturally inside surrounding prose in both modes. The exported SVG omits the
scene background so it inherits the page surface.
D2
Verto supports D2 diagrams in the same two equivalent forms as Mermaid.
As a fenced code block
A rehype-d2 plugin intercepts these blocks before Shiki sees them and
routes them to the client-side D2 renderer.
As an MDX component
For when you want to mix props, conditionals, or data binding into the source:
Safety
The rendered SVG is sanitized through DOMPurify before being injected into the DOM, so even an attacker-crafted D2 source cannot smuggle script tags into the page.
Theming
Pass themeId and darkThemeId props to pick from D2's
built-in themes. Defaults are the neutral
light theme (id 0) and D2's dark theme (id 200). The diagram re-renders
automatically when the user toggles light / dark mode.
Performance
All three renderers are loaded lazily so they never weigh down pages that don't use them:
- Mermaid — the ~1 MB bundle is dynamic-imported on first use.
- Excalidraw — dynamic-imported, then each scene is exported to an inline read-only SVG at build / load time.
- D2 — the ~3 MB WASM bundle is dynamic-imported, and its output is DOMPurify-sanitized before injection.
In every case, pages without that diagram type pay zero bundle cost, and the diagram re-renders on light / dark toggle.
Related
- Block Components — including the
DiagramPlaceholderfor sketching out a diagram before you draw it - MDX Authoring for the full MDX writing guide
- Syntax Highlighting for how fenced code blocks are highlighted when they aren't diagrams