Render Mermaid diagrams to SVG in pure .NET.
No browser. No DOM. No JavaScript runtime. AOT-ready.
Table of Contents
- Why Mermaider?
- Quick Start
- Theming
- Render Options
- Strict Styling
- SVG Sanitization
- CLI
- MSAGL Layout Provider
- AOT Support
- Benchmarks
- Building from Source
- Supported Diagrams
- Attribution
- Projects using Mermaider
- License
Why Mermaider?
Mermaider is a complete Mermaid parser, layout engine, and SVG renderer built entirely in .NET. Hand it a Mermaid string; get a sanitized, consistently styled SVG back. No interop, no child processes, no headless browsers.
It covers all 24 major Mermaid diagram types, always-on allowlist SVG sanitization with no opt-out,
and a unified design-token model so every diagram type renders from the same RenderOptions — one API,
one theming model, consistent output regardless of diagram type.
What makes it stand out
- Pure .NET, zero interop: just a NuGet reference. No Chromium, no Node.js, no subprocess management.
- Native AOT: every public API proven in CI on Linux, macOS, and Windows.
- Built-in layout engine: zero-dependency Sugiyama, far leaner than MSAGL.
- 24 diagram types: one API, one theming model for all of them.
- Unified theming: 15 themes, live-switchable via CSS custom properties.
- Always-on SVG sanitization: allowlist-only, no opt-out.
- Strict styling mode: enforce your design system on user-authored diagrams.
- Fast: ~23 µs, ~46 KB allocated for a simple flowchart.
Pure .NET parsing and rendering
Mermaider parses Mermaid's text DSL and renders SVG output using only managed .NET code. There is no dependency on JavaScript, Chromium, or any external process. This means deterministic output, no cold-start penalty, and trivial deployment: just a NuGet reference.
Built-in layout engine
Graph-based diagrams (flowchart, state, class, ER) need a layout algorithm to position nodes and route edges. Other diagram types (pie, quadrant, timeline, gitgraph, radar, treemap, venn, mindmap, gantt, journey, C4, sankey, xychart, requirement, packet, kanban, architecture, block, treeview) use purpose-built layout arithmetic directly in their renderers. Rather than depending on an external engine, Mermaider ships its own lightweight Sugiyama layout engine with zero dependencies.
During development, Microsoft MSAGL (Automatic Graph
Layout) was evaluated as the layout backend. MSAGL is a capable research-grade library, but it carries
baggage from a different era of .NET: high allocations (~554 KB for a 6-node flowchart), WPF-era
BinaryFormatter usage, and trim/AOT warnings that make it unsuitable for modern deployment targets.
The built-in engine is purpose-built for the small-to-medium directed graphs Mermaid produces:
| Phase | MSAGL | Built-in Sugiyama | Improvement |
|---|---|---|---|
| Layout only | 247 µs / 558 KB | 3.4 µs / 16 KB | 73× faster, 35× less memory |
| End-to-end render | 351 µs / 586 KB | 24 µs / 46 KB | 15× faster, 13× less memory |
If you still want MSAGL for its higher-fidelity edge routing on complex graphs, install the optional
Mermaider.Layout.Msagl package (see below).
Native AOT
Every public API is compatible with .NET Native AOT. The CI pipeline publishes and invokes a native binary on Linux, macOS, and Windows to prove it. No reflection, no runtime code generation, no surprises.
Security and normalized styling
Security and visual consistency are not afterthoughts when embedding user-authored diagrams. Both shaped Mermaider's design from the start.
Safety
Every rendered SVG passes through an element/attribute allowlist before leaving the library. There is no way to opt out. The allowlist is the only gate:
<script>,<foreignObject>, and event handlers are absent from the allowlist, not pattern-matched- External
hrefURIs are structurally excluded; the only permittedhrefis a base64data:image/svg+xmlordata:image/pngon an<image>element - A second sanitizer pass on any output is always a no-op, proving convergence
Coverage: unit tests and a deterministic fuzzer with 4,000 generated cases across mutation and structured element/attribute/value cross-products.
Visual consistency
All 24 diagram types render from the same RenderOptions. A single set of values controls:
- Colors:
Bg,Fg,Accent,Muted,Surface,Border,Line - Typography:
Font,MonoFont,FontSizeand size ratios - Data palette: categorical colors for pie, sankey, timeline, gitgraph, and the rest
There is no per-type color system or per-type font stack. The design token model is the only model.
Strict Styling goes further for user-authored content: classDef, style, linkStyle, and theme overrides are stripped (and optionally reported via callback), and nodes are constrained to a class allowlist you define.
Quick Start
dotnet add package Mermaider
using Mermaider; var svg = MermaidRenderer.RenderSvg(""" graph TD A[Start] --> B{Decision} B -->|Yes| C[OK] B -->|No| D[End] """);
Theming
Every diagram derives its palette from just two colors (background and foreground) using
color-mix() CSS functions embedded in the SVG. Override individual roles for richer themes:
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { Bg = "#1E1E2E", Fg = "#CDD6F4", Accent = "#CBA6F7", // arrow heads, highlights Muted = "#6C7086", // secondary text, edge labels });
Because the SVG uses CSS custom properties, themes switch live without re-rendering: just update the
--bg / --fg properties on the root <svg> element.
Built-in themes
15 themes ship out of the box. Pass the name via the theme init directive in your diagram source, or
resolve one programmatically:
var colors = Themes.BuiltIn["tokyo-night"]; var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { Bg = colors.Bg, Fg = colors.Fg, Accent = colors.Accent, Muted = colors.Muted, });
| Theme | Style |
|---|---|
zinc-light |
Default light |
zinc-dark |
Default dark |
tokyo-night / tokyo-night-storm / tokyo-night-light |
Tokyo Night family |
catppuccin-mocha / catppuccin-latte |
Catppuccin |
nord / nord-light |
Nord |
dracula |
Dracula |
github-light / github-dark |
GitHub |
solarized-light / solarized-dark |
Solarized |
one-dark |
One Dark |
Dark themes automatically ship a brighter data palette (pie slices, sankey nodes, timeline bands, etc.) that maintains legibility on dark backgrounds. You can override the data palette entirely:
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { DataPalette = ["#ff6b6b", "#feca57", "#48dbfb", "#ff9ff3", "#54a0ff"], });
Render Options
| Option | Type | Default | Description |
|---|---|---|---|
Bg |
string? |
"#FFFFFF" |
Background color (hex or CSS) |
Fg |
string? |
"#27272A" |
Foreground / primary text color |
Line |
string? |
derived | Edge/connector stroke color |
Accent |
string? |
derived | Arrowheads, highlights |
Muted |
string? |
derived | Secondary text, edge labels |
Surface |
string? |
derived | Node fill tint |
Border |
string? |
derived | Node/group stroke |
Font |
string? |
"Inter" |
Font family for all text |
MonoFont |
string? |
system stack | Monospace font for ER attribute types and Class member signatures |
FontSize |
string? |
"1rem" |
Base font size (--fs-m). Accepts px, rem, em, and % units |
FontSizeSmall |
double? |
0.875 |
Ratio for small text (--fs-s) |
FontSizeExtraSmall |
double? |
0.75 |
Ratio for extra-small text (--fs-xs) |
FontSizeLarge |
double? |
1.125 |
Ratio for large text (--fs-l) |
DataPalette |
string[]? |
theme default | Categorical colors for pie, sankey, timeline, gitgraph, radar, mindmap, venn, journey, packet, xychart, treemap |
AllowedDiagrams |
DiagramTypes |
DiagramTypes.All |
Allowlist of accepted diagram types; diagrams outside this set throw MermaidParseException |
RoundedEdges |
bool |
true |
Rounded corners (6px radius) on edge paths |
Transparent |
bool |
true |
Transparent background |
Padding |
double? |
40 |
Canvas padding in px |
NodeSpacing |
double? |
28 |
Horizontal spacing between sibling nodes |
LayerSpacing |
double? |
56 |
Vertical spacing between layers |
Strict |
StrictStylingOptions? |
null |
Optional host-controlled styling policy |
SanitizeMode |
SanitizeMode |
Strip |
Strip SVG violations, or throw MermaidSvgException in Block mode |
Font options
Both Font and MonoFont accept a font-family name (not an arbitrary CSS declaration):
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { Font = "system-ui", // sans-serif system font MonoFont = "ui-monospace", // system monospace (e.g. SF Mono, Cascadia) });
Generic CSS keywords (monospace, sans-serif, serif, etc.) are passed unquoted as required by CSS.
Named fonts are automatically quoted: 'Courier New', 'JetBrains Mono', etc.
Data palette
Color-encoded diagram types (pie, sankey, timeline, gitgraph, radar, mindmap, venn, journey, packet,
xychart, treemap) all draw from a single 12-color Tableau-derived palette. Dark themes ship a brightened
variant automatically. Use DataPalette to supply your own colors:
// Brand colors for pie/sankey/etc. var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { DataPalette = ["#0f62fe", "#da1e28", "#198038", "#f1c21b"], });
The CategoricalPalette class exposes all 12 colors by semantic name for use in custom logic:
using Mermaider.Rendering; // Named colors (index-stable) string blue = CategoricalPalette.Blue; // #4e79a7 string red = CategoricalPalette.Red; // #e15759 string green = CategoricalPalette.Green; // #59a14f // Dark variants (same hue, ~20% lower lightness — suitable for strokes/borders) string redDark = CategoricalPalette.RedDark; string blueDark = CategoricalPalette.BlueDark; // Ordinal access (wraps at 12) string color = CategoricalPalette.At(7); // Pink
Allowed diagram types
AllowedDiagrams is a [Flags] enum that controls which diagram types the renderer will accept.
Diagrams whose detected type is outside the set throw MermaidParseException. The default is
DiagramTypes.All.
// Stable diagrams only, plus Architecture: var opts = new RenderOptions { AllowedDiagrams = DiagramTypes.Stable | DiagramTypes.Architecture, }; // Everything except TreeView and Block: var opts = new RenderOptions { AllowedDiagrams = DiagramTypes.All & ~(DiagramTypes.TreeView | DiagramTypes.Block), }; // Only flowcharts and sequence diagrams: var opts = new RenderOptions { AllowedDiagrams = DiagramTypes.Flowchart | DiagramTypes.Sequence, };
Named sets:
| Set | Contents |
|---|---|
DiagramTypes.All |
All 24 diagram types (default) |
DiagramTypes.Stable |
15 types with stable Mermaid syntax (no -beta keyword) |
DiagramTypes.Beta |
9 types that use a -beta keyword (radar-beta, architecture-beta, etc.) |
Edge rounding
Edges use rounded corners by default (6px radius). To render straight/angular edges instead:
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { RoundedEdges = false, });
Font sizing
Font sizes are emitted as CSS custom properties in the SVG <style> block:
:root { --fs-xs: 0.75rem; --fs-s: 0.875rem; --fs-m: 1rem; --fs-l: 1.125rem; }
All text elements reference these variables, so downstream consumers can override sizing by
redefining the custom properties on the <svg> element without re-rendering.
Strict Styling
Strict styling is about visual uniformity, not safety. It does not make output safe to publish. SVG sanitization does that, and it is always on regardless of this setting. Use strict styling when you want a consistent look controlled by your design system rather than by whatever colors a diagram author wrote.
When you embed user-authored Mermaid in a product, you typically want uniform styling controlled by your
design system, not arbitrary colors injected via classDef or style directives.
Strict styling:
- Strips
classDef,style, andlinkStyledirectives (diagram renders; violations reported viaOnStripped) - Strips source-authored
theme/themeVariablesoverrides from%%{init}%%and frontmatter - Strips C4
UpdateElementStyle/UpdateRelStyle/UpdateBoundaryStyle - Enforces a pre-approved class allowlist with theme-aware colors
- Generates
@media (prefers-color-scheme: dark)CSS for automatic light/dark switching - Auto-derives dark mode colors by inverting HSL lightness (or use explicit overrides)
The default mode is StrictStylingMode.Strip — disallowed directives and unknown class references are silently dropped and the diagram still renders. Wire OnStripped to log what was dropped:
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { Strict = new StrictStylingOptions { AllowedClasses = [ new DiagramClass { Name = "ok", Fill = "#D4EDDA", Stroke = "#28A745", Color = "#155724", }, new DiagramClass { Name = "warn", Fill = "#FFF3CD", Stroke = "#FFC107", Color = "#856404", }, new DiagramClass { Name = "custom-highlight" }, ], OnStripped = v => logger.LogWarning("Strict mode stripped {Kind}: {Message}", v.Kind, v.Message), } });
Set Mode = StrictStylingMode.Block to throw MermaidParseException instead (the original fail-closed behavior):
Strict = new StrictStylingOptions { Mode = StrictStylingMode.Block, AllowedClasses = [ ... ], }
Nodes reference classes via Mermaid's ::: shorthand or class directive:
graph TD
A[Healthy]:::ok --> B[Warning]:::warn --> C[Custom]:::custom-highlight
SVG Sanitization
Sanitization is the safety mechanism, and it is always on. Every rendered SVG is run through an
element/attribute allowlist on every RenderSvg call before it leaves the library. There is no way to
turn it off, and it is completely independent of strict styling. This is defense-in-depth on
top of the per-renderer output escaping: even if a renderer had a bug, disallowed markup cannot reach a
published page.
The sanitizer is allowlist-only: anything not explicitly affirmed as safe is removed. There is deliberately
no blocklist of "known bad" constructs. Safety never depends on us having enumerated every dangerous
attribute. Because they are absent from the allowlist, the main XSS vectors are denied as a consequence:
<script>, <foreignObject>, on* event handlers, and href/xlink:href with javascript:/http(s):/
non-image data URIs. The single positive exception is a base64 data:image/svg+xml or data:image/png
URI href on an <image> element (used for diagram icons).
The renderer-only stylesheet is accepted through a separate exact generated grammar. Standalone
untrusted SVG cannot retain <style> elements or style attributes. Custom sanitizer allowlists can
only narrow the built-in safety sets; they cannot opt a new element or attribute into the policy.
Use RenderOptions.SanitizeMode to choose what happens when the output contains a violation (which, for the
built-in renderers, should never happen; it indicates a bug):
SanitizeMode.Strip(default): remove disallowed content from well-formed SVG and return the stripped document. If the generated output is not well-formed XML, returnMermaidRenderer.FallbackSvg, the canonical empty SVG document.SanitizeMode.Block: throwMermaidSvgExceptionwith all detected violations (fail closed).
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { SanitizeMode = SanitizeMode.Block, // fail closed instead of silently stripping });
In Strip mode (the default), use OnSanitized to receive a callback for each removed violation instead of discovering them silently:
var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { OnSanitized = v => logger.LogWarning("SVG sanitizer removed {Kind} '{Name}'", v.Kind, v.Name), });
The same engine is also exposed standalone, useful beyond Mermaid for any untrusted SVG content:
var result = SvgSanitizer.Sanitize(untrustedSvg); if (result.HasViolations) Console.WriteLine($"Stripped {result.Violations.Count} violations"); var cleanSvg = result.Svg;
Malformed XML produces MermaidRenderer.FallbackSvg and a malformed-xml violation in the result.
To reject instead, call SvgSanitizer.Sanitize(untrustedSvg, SanitizeMode.Block); it throws
MermaidSvgException. A well-formed document with violations is always returned stripped by the
non-throwing overload; safe siblings are preserved.
CLI
dotnet tool install -g Mermaider.Cli echo 'graph TD A --> B' | mermaid > diagram.svg mermaid input.mmd -o output.svg --theme github-dark mermaid --list-themes
MSAGL Layout Provider
If you prefer MSAGL for its edge routing fidelity on complex graphs, install the optional package:
dotnet add package Mermaider.Layout.Msagl
using Mermaider.Layout.Msagl; // Global — all subsequent renders use MSAGL: MermaidRenderer.SetLayoutProvider(new MsaglLayoutProvider()); // Or per-call: var svg = MermaidRenderer.RenderSvg(input, new RenderOptions { LayoutProvider = new MsaglLayoutProvider(), });
AOT Support
Mermaider is fully compatible with .NET Native AOT. To publish your own AOT app:
<PropertyGroup> <PublishAot>true</PublishAot> </PropertyGroup> <ItemGroup> <PackageReference Include="Mermaider" /> </ItemGroup>
dotnet publish -c Release
Benchmarks
Graph-based diagram types use the built-in Sugiyama engine. Measured with [MemoryDiagnoser] on .NET 10
(Apple M2 Pro):
| Method | Mean | Allocated |
|---|---|---|
| Flowchart (simple) | ~23 µs | ~46 KB |
| Flowchart (large) | ~71 µs | ~145 KB |
| Sequence | ~12 µs | ~28 KB |
| State | ~17 µs | ~47 KB |
| Class | ~13 µs | ~36 KB |
| ER | ~17 µs | ~45 KB |
dotnet run --project tests/Mermaider.Benchmarks -c Release
Building from Source
git clone https://github.com/nullean/mermaider.git cd mermaider ./build.sh build ./build.sh test
Supported Diagrams
Mermaider renders all major Mermaid diagram types to SVG. The design model is normalized across all
types. Every diagram respects the same Bg, Fg, Accent, Muted, Font, MonoFont, and
DataPalette options.
Flowchart
MermaidRenderer.RenderSvg(""" graph TD A[Start] --> B{Decision} B -->|Yes| C[OK] B -->|No| D[Cancel] C --> E[End] D --> E """);
Sequence
MermaidRenderer.RenderSvg(""" sequenceDiagram participant A as Alice participant B as Bob A->>B: Hello Bob! B-->>A: Hi Alice! A->>B: How are you? B-->>A: Great, thanks! """);
State
MermaidRenderer.RenderSvg(""" stateDiagram-v2 [*] --> Idle Idle --> Processing : submit Processing --> Success : ok Processing --> Failed : error Success --> [*] Failed --> Idle : retry """);
Class
MermaidRenderer.RenderSvg(""" classDiagram class Animal { <<abstract>> +String name +eat() void } class Dog { +bark() void } class Cat { +purr() void } Animal <|-- Dog Animal <|-- Cat """);
ER (Entity-Relationship)
MermaidRenderer.RenderSvg(""" erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE_ITEM : contains CUSTOMER { string name PK string email UK } ORDER { int id PK date created } """);
Pie Chart
MermaidRenderer.RenderSvg(""" pie title Pet Adoption "Dogs" : 386 "Cats" : 85 "Rats" : 15 """);
Quadrant Chart
MermaidRenderer.RenderSvg(""" quadrantChart title Priority Matrix x-axis Low Effort --> High Effort y-axis Low Impact --> High Impact quadrant-1 Do First quadrant-2 Schedule quadrant-3 Delegate quadrant-4 Eliminate Feature A: [0.8, 0.9] Feature B: [0.2, 0.3] Feature C: [0.6, 0.4] """);
Timeline
MermaidRenderer.RenderSvg(""" timeline title History of Social Media section Early Days 2002 : LinkedIn 2004 : Facebook : Google section Modern Era 2010 : Instagram 2019 : TikTok """);
GitGraph
MermaidRenderer.RenderSvg(""" gitGraph commit id: "init" commit id: "feat-1" branch develop checkout develop commit id: "dev-1" commit id: "dev-2" tag: "v0.1" checkout main merge develop id: "merge-1" commit id: "release" type: HIGHLIGHT tag: "v1.0" """);
Radar Chart
MermaidRenderer.RenderSvg(""" radar-beta title Skills Assessment axis Design, Frontend, Backend, DevOps, Testing curve c1["Team A"]{4, 3, 5, 2, 4} curve c2["Team B"]{3, 5, 2, 4, 3} max 5 graticule polygon """);
Treemap
MermaidRenderer.RenderSvg(""" treemap-beta "Engineering": 50 "Marketing": 25 "Sales": 15 "Support": 10 """);
Venn Diagram
MermaidRenderer.RenderSvg(""" venn-beta set A["Frontend"] set B["Backend"] set C["DevOps"] union A, B["Full Stack"] union B, C["SRE"] """);
Mindmap
MermaidRenderer.RenderSvg(""" mindmap ((Project)) (Planning) Requirements Timeline [Development] Frontend Backend {{Testing}} Unit Tests Integration """);
Gantt
MermaidRenderer.RenderSvg(""" gantt title Shipping this file dateFormat YYYY-MM-DD section Render Spike the renderer :done, a1, 2026-07-07, 1d Print this page :active, a2, after a1, 1d section Polish Update tests :crit, after a2, 12h Update docs : 6h """);
User Journey
MermaidRenderer.RenderSvg(""" journey title My working day section Go to work Make tea: 5: Me Go upstairs: 3: Me Do work: 1: Me, Cat section Go home Go downstairs: 5: Me Sit down: 5: Me """);
C4 Architecture
MermaidRenderer.RenderSvg(""" C4Context title System Context diagram for Internet Banking System Person(customer, "Banking Customer", "A customer of the bank.") System(banking, "Internet Banking System", "View accounts and make payments.") System_Ext(mail, "E-mail System", "Microsoft Exchange") Rel(customer, banking, "Uses") Rel(banking, mail, "Sends e-mails", "SMTP") """);
Supports Rel, BiRel, Rel_Back (arrow reversed vs argument order), and RelIndex. Directional forms (Rel_U / Rel_D / Rel_L / Rel_R and aliases) parse as plain Rel; layout direction hints are ignored in v1.
Sankey Diagram
MermaidRenderer.RenderSvg(""" sankey-beta Electricity grid,Over generation / exports,104.453 Electricity grid,Heating and cooling - homes,113.726 Electricity grid,Industry,342.165 """);
XY Chart
MermaidRenderer.RenderSvg(""" xychart-beta title "Sales Revenue" x-axis [jan, feb, mar, apr, may, jun] y-axis "Revenue (in $)" 4000 --> 11000 bar [5000, 6000, 7500, 8200, 9500, 10500] line [5000, 6000, 7500, 8200, 9500, 10500] """);
Requirement Diagram
MermaidRenderer.RenderSvg(""" requirementDiagram requirement test_req { id: 1 text: the test text. risk: high verifymethod: test } element test_entity { type: simulation } test_entity - satisfies -> test_req """);
Packet Diagram
MermaidRenderer.RenderSvg(""" packet-beta title UDP Header 0-15: "Source Port" 16-31: "Destination Port" 32-47: "Length" 48-63: "Checksum" """);
Supports range fields (0-15: "Label"), single-bit fields (106: "URG"), and bit-count form (+16: "Source Port").
Kanban
MermaidRenderer.RenderSvg(""" kanban Todo Task1 Task2 In Progress Task3 Done Task4 """);
Architecture
MermaidRenderer.RenderSvg(""" architecture-beta group k8s(cloud)[k8s] group ech(cloud)[ECH] service edot(server)[EDOT] in k8s service oteldemo(server)[OtelDemo] in k8s service es(elastic:elasticsearch)[Elasticsearch] in ech service kbn(elastic:kibana)[Kibana] in ech service apm(elastic:apm)[APM] in ech junction otlp edot:L -- R:otlp otlp:L -- T:apm oteldemo:L -- R:edot kbn:L -- T:es apm:L -- R:es """);
Built-in icons
Icons resolve through Mermaider.Icons.IconRegistry, referenced in a diagram as service id(iconName)[Title].
| Pack | Icons |
|---|---|
| Default (no prefix) | cloud, database, disk, internet, server, generic |
aws: / azure: / gcp: |
compute, storage, database, networking, serverless, load-balancer, queue, cdn, cache |
elastic: |
elasticsearch, kibana, logstash, beats, fleet, serverless, apm, security, observability |
ext: (vendor-neutral) |
waf, api-gateway, k8s, pod, pool, reverse-proxy, web, api, load-balancer, queue, cdn, cache |
The vendor and ext: icons are original, simplified pictograms, not the vendors'
official trademarked artwork. AWS/Azure/GCP's real icon sets are licensed for use in your own
diagrams, not for bundling into a redistributable library, which is why these are bespoke
shapes; register the real logos yourself (see below) if you have the rights to use them.
They render with a colored gradient badge behind them (vendor hue for
aws:/azure:/gcp:/elastic:, neutral slate for ext:). Default-pack icons render plainly
on the themed node box instead.
Adding your own icons
Register any SVG under a name of your choosing, including bare names or pack:icon style
names to group related icons:
using Mermaider.Icons; IconRegistry.Register("mycompany:widget", """ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="8" fill="#0f62fe"/> </svg> """);
architecture-beta
service w(mycompany:widget)[Widget]
Register also has ReadOnlySpan<byte> and Stream overloads for loading icons from disk or
embedded resources without decoding them yourself:
IconRegistry.Register("mycompany:logo", File.ReadAllBytes("logo.svg")); using var stream = typeof(Program).Assembly.GetManifestResourceStream("MyApp.Icons.logo.svg")!; IconRegistry.Register("mycompany:logo", stream);
Regardless of which overload you use, every registered icon is stored as sanitized SVG text and
rendered the same way: as a base64 data URL on an <image> element
(<image href="data:image/svg+xml;base64,...">), sized and centered in the service box.
Registration validates and sanitizes the SVG using the same allowlist as
SvgSanitizer: <script> tags, event-handler attributes, and any
href other than a validated base64 data:image/svg+xml/data:image/png URI are rejected outright
(MermaidSvgException), not silently stripped. Custom icons render inside the plain themed node
box, same as the default pack. The colored gradient badge is only applied to the built-in
vendor/ext: icons. If you have the rights to use a vendor's real logo (e.g. inside your own
company's tooling), register it under whatever name you like and it renders exactly as provided.
Block Diagram
MermaidRenderer.RenderSvg(""" block-beta columns 3 A["A"] B["B"] C["C"] D["D"] E["E"] F["F"] """);
TreeView
MermaidRenderer.RenderSvg(""" treeView-beta my-project/ src/ index.ts :::highlight ## entry point utils.ts tests/ index.test.ts package.json README.md """);
Supports indentation-based and box-drawing (├──/└──/│) input formats. Annotations:
:::className (highlighting), ## description (inline notes), icon(name) (custom icons).
Built-in icons: file, folder, folder-open, file:code, file:image, file:document,
file:config, file:data.
Attribution
This project started as a .NET port of beautiful-mermaid by Craft Docs (lukilabs). Their TypeScript library pioneered the idea of rendering Mermaid diagrams without a browser or DOM: fast, themeable, and synchronous.
beautiful-mermaid itself credits mermaid-ascii by
Alexander Grooff for its ASCII rendering engine, which was ported from Go to TypeScript and extended.
beautiful-mermaid, relies on an external battle hardened layout engine elk.js,
We owe a huge thank-you to both projects for the excellent foundation.
A note on how this was built
This codebase was written with a coding agent (Claude). That said, care was taken to follow modern .NET 10
idioms and keep allocations low: ReadOnlySpan<char> parsing, [GeneratedRegex] with ReDoS timeout guards,
FrozenDictionary / FrozenSet for hot-path lookups, SearchValues<char> for character classification,
object pooling, and file-scoped namespaces throughout. The benchmark numbers above reflect the result.
Projects using Mermaider
Projects that use Mermaider and have contributed back:
- elastic/docs-builder - Elastic's documentation build toolchain
- tig/winprint - WinPrint uses Mermaider as its default Mermaid renderer
License
MIT. See LICENSE.txt.
