Mermaid diagrams
Render fenced mermaid blocks as SVG, through an entry point that keeps mermaid out of every other bundle.
shikidown recognises ```mermaid fences natively — no markdown-it plugin required. Instead of
highlighting the fence, MarkdownService emits a placeholder:
<pre class="mermaid" data-mermaid-src="…">graph TD…</pre>Turning that placeholder into an SVG is the job of MermaidDirective, which lives in its own entry
point.
Setup
Add the directive
import { MarkdownComponent } from 'shikidown';
import { MermaidDirective } from 'shikidown/mermaid';
@Component({
selector: 'app-docs',
imports: [MarkdownComponent, MermaidDirective],
template: `<shikidown mermaid [content]="markdown" />`,
})
export class DocsComponent {
readonly markdown = '```mermaid\ngraph TD\n A[Start] --> B{Choice}\n```';
}MermaidDirective has an attribute selector, [mermaid], and takes no inputs.
Without the directive, ```mermaid blocks stay rendered as inert code. That is a deliberate,
harmless fallback rather than an error.
Why a separate entry point
mermaid is large, and most applications never draw a diagram. It is therefore reachable only
through shikidown/mermaid:
import { MermaidDirective } from 'shikidown/mermaid'; // ← the only doorIf you never import from that path, mermaid never enters your dependency graph. And even when you
do, the package itself is fetched with a dynamic import('mermaid') the first time the directive
runs — never during SSR, never before it is needed.
How rendering is driven
The directive is event-driven rather than re-running on every change detection cycle. It
installs two MutationObservers:
- one on its host element, watching for diagram placeholders newly inserted by shikidown — which is what makes it work with asynchronous and incremental rendering;
- one on
<html>, watching theclassattribute for a dark/light switch.
Work is coalesced through a microtask, so the burst of mutations mermaid itself produces while drawing does not trigger a second pass. Nothing runs while nothing changes, and rendering is scoped to the host element rather than the whole document.
Dark mode
On a theme change the directive re-initialises mermaid with theme: 'dark' or theme: 'default',
then rearms already-rendered diagrams by restoring their source from data-mermaid-src and clearing
data-processed. Diagrams are redrawn in the new theme without touching [content].
The trigger is the dark class on <html> — the same convention used by
Styling and dark mode.
Security
The directive initialises mermaid with securityLevel: 'strict': HTML in labels is encoded and
click handlers are disabled. For interactive diagrams you trust, opt into 'loose':
<shikidown mermaid mermaidSecurityLevel="loose" [content]="markdown" />'loose' allows click handlers and raw HTML inside diagram labels. Never use it for diagrams
produced by an LLM or a user. See Content security.
Invalid diagrams and streaming
Each diagram is parsed before rendering. An invalid one keeps its source on screen, marked with
data-mermaid-error, without preventing the others from rendering. In
streaming mode, the pre.mermaid placeholder is only emitted once the
fence is closed: an unfinished diagram is shown as code, never half-rendered.
Example
```mermaid
flowchart LR
Editor -->|content| shikidown
shikidown -->|pre.mermaid| MermaidDirective
MermaidDirective -->|SVG| DOM
```