Overview
Mermaid can be integrated into various frameworks and build systems. This guide provides practical integration patterns for popular frameworks, along with examples and best practices from the source code.Module formats
Mermaid is available in multiple module formats:- ESM (recommended):
mermaid.esm.min.mjs - UMD:
mermaid.min.js - Tiny version: Approximately half the size, without Mindmap, Architecture, KaTeX, or lazy loading
ESM import (recommended)
Fromusage.md:66:
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
</script>
import mermaid from 'mermaid';
React integration
Using hooks
import { useEffect, useRef, useState } from 'react';
import mermaid from 'mermaid';
// Initialize once
mermaid.initialize({
startOnLoad: false,
theme: 'default'
});
interface MermaidProps {
chart: string;
id?: string;
}
export const Mermaid: React.FC<MermaidProps> = ({ chart, id = 'mermaid' }) => {
const containerRef = useRef<HTMLDivElement>(null);
const [svg, setSvg] = useState<string>('');
const [error, setError] = useState<string>('');
useEffect(() => {
const renderDiagram = async () => {
if (!containerRef.current) return;
try {
// Generate unique ID for each render
const uniqueId = `${id}-${Date.now()}`;
// Render the diagram
const { svg, bindFunctions } = await mermaid.render(uniqueId, chart);
setSvg(svg);
setError('');
// Bind interactive functions after SVG is in DOM
if (containerRef.current && bindFunctions) {
setTimeout(() => {
bindFunctions(containerRef.current!);
}, 0);
}
} catch (err) {
console.error('Mermaid rendering error:', err);
setError(err instanceof Error ? err.message : 'Unknown error');
}
};
renderDiagram();
}, [chart, id]);
if (error) {
return (
<div style={{ color: 'red', border: '1px solid red', padding: '10px' }}>
<strong>Error rendering diagram:</strong> {error}
</div>
);
}
return (
<div
ref={containerRef}
dangerouslySetInnerHTML={{ __html: svg }}
/>
);
};
Usage in React component
import { Mermaid } from './components/Mermaid';
function App() {
const diagram = `
flowchart TD
A[Start] --> B{Decision}
B -->|Yes| C[Action 1]
B -->|No| D[Action 2]
`;
return (
<div>
<h1>My Diagram</h1>
<Mermaid chart={diagram} />
</div>
);
}
Class component version
import React from 'react';
import mermaid from 'mermaid';
mermaid.initialize({ startOnLoad: false });
interface Props {
chart: string;
}
interface State {
svg: string;
}
export class MermaidDiagram extends React.Component<Props, State> {
private containerRef = React.createRef<HTMLDivElement>();
state: State = {
svg: ''
};
async componentDidMount() {
await this.renderDiagram();
}
async componentDidUpdate(prevProps: Props) {
if (prevProps.chart !== this.props.chart) {
await this.renderDiagram();
}
}
async renderDiagram() {
try {
const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
const { svg, bindFunctions } = await mermaid.render(id, this.props.chart);
this.setState({ svg }, () => {
if (this.containerRef.current && bindFunctions) {
bindFunctions(this.containerRef.current);
}
});
} catch (error) {
console.error('Error rendering diagram:', error);
}
}
render() {
return (
<div
ref={this.containerRef}
dangerouslySetInnerHTML={{ __html: this.state.svg }}
/>
);
}
}
Vue integration
Vue 3 composition API
<template>
<div ref="containerRef" v-html="svg"></div>
<div v-if="error" class="error">
<strong>Error:</strong> {{ error }}
</div>
</template>
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue';
import mermaid from 'mermaid';
interface Props {
chart: string;
id?: string;
}
const props = withDefaults(defineProps<Props>(), {
id: 'mermaid'
});
const containerRef = ref<HTMLElement>();
const svg = ref('');
const error = ref('');
mermaid.initialize({ startOnLoad: false });
const renderDiagram = async () => {
try {
const uniqueId = `${props.id}-${Date.now()}`;
const result = await mermaid.render(uniqueId, props.chart);
svg.value = result.svg;
error.value = '';
// Bind functions after DOM update
await nextTick();
if (containerRef.value && result.bindFunctions) {
result.bindFunctions(containerRef.value);
}
} catch (err) {
console.error('Mermaid error:', err);
error.value = err instanceof Error ? err.message : 'Unknown error';
}
};
watch(() => props.chart, renderDiagram);
onMounted(renderDiagram);
</script>
<style scoped>
.error {
color: red;
border: 1px solid red;
padding: 10px;
margin: 10px 0;
}
</style>
Vue 2 options API
<template>
<div ref="container" v-html="svg"></div>
</template>
<script>
import mermaid from 'mermaid';
mermaid.initialize({ startOnLoad: false });
export default {
props: {
chart: {
type: String,
required: true
}
},
data() {
return {
svg: ''
};
},
watch: {
chart() {
this.renderDiagram();
}
},
mounted() {
this.renderDiagram();
},
methods: {
async renderDiagram() {
try {
const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`;
const { svg, bindFunctions } = await mermaid.render(id, this.chart);
this.svg = svg;
this.$nextTick(() => {
if (this.$refs.container && bindFunctions) {
bindFunctions(this.$refs.container);
}
});
} catch (error) {
console.error('Mermaid render error:', error);
}
}
}
};
</script>
Angular integration
Mermaid service
// mermaid.service.ts
import { Injectable } from '@angular/core';
import mermaid from 'mermaid';
@Injectable({
providedIn: 'root'
})
export class MermaidService {
private initialized = false;
constructor() {
this.initialize();
}
private initialize() {
if (!this.initialized) {
mermaid.initialize({
startOnLoad: false,
theme: 'default'
});
this.initialized = true;
}
}
async render(id: string, definition: string): Promise<{ svg: string; bindFunctions?: (element: Element) => void }> {
try {
return await mermaid.render(id, definition);
} catch (error) {
console.error('Mermaid rendering error:', error);
throw error;
}
}
}
Mermaid component
// mermaid.component.ts
import { Component, Input, ElementRef, ViewChild, OnChanges, AfterViewInit } from '@angular/core';
import { MermaidService } from './mermaid.service';
@Component({
selector: 'app-mermaid',
template: `
<div #container></div>
<div *ngIf="error" class="error">
<strong>Error:</strong> {{ error }}
</div>
`,
styles: [`
.error {
color: red;
border: 1px solid red;
padding: 10px;
margin: 10px 0;
}
`]
})
export class MermaidComponent implements OnChanges, AfterViewInit {
@Input() chart: string = '';
@Input() id: string = 'mermaid';
@ViewChild('container', { static: true }) container!: ElementRef;
error: string = '';
private viewInitialized = false;
constructor(private mermaidService: MermaidService) {}
ngAfterViewInit() {
this.viewInitialized = true;
this.renderDiagram();
}
ngOnChanges() {
if (this.viewInitialized) {
this.renderDiagram();
}
}
private async renderDiagram() {
if (!this.chart || !this.container) return;
try {
const uniqueId = `${this.id}-${Date.now()}`;
const { svg, bindFunctions } = await this.mermaidService.render(uniqueId, this.chart);
this.container.nativeElement.innerHTML = svg;
this.error = '';
if (bindFunctions) {
bindFunctions(this.container.nativeElement);
}
} catch (err) {
this.error = err instanceof Error ? err.message : 'Unknown error';
}
}
}
Usage in Angular template
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h1>Mermaid Diagram</h1>
<app-mermaid [chart]="diagram"></app-mermaid>
`
})
export class AppComponent {
diagram = `
graph TD
A[Start] --> B{Decision}
B -->|Yes| C[End 1]
B -->|No| D[End 2]
`;
}
Svelte integration
<script>
import { onMount, onDestroy } from 'svelte';
import mermaid from 'mermaid';
export let chart = '';
export let id = 'mermaid';
let container;
let svg = '';
let error = '';
mermaid.initialize({ startOnLoad: false });
async function renderDiagram() {
if (!chart) return;
try {
const uniqueId = `${id}-${Date.now()}`;
const result = await mermaid.render(uniqueId, chart);
svg = result.svg;
error = '';
// Bind functions after DOM update
setTimeout(() => {
if (container && result.bindFunctions) {
result.bindFunctions(container);
}
}, 0);
} catch (err) {
console.error('Mermaid error:', err);
error = err.message || 'Unknown error';
}
}
$: if (chart) renderDiagram();
onMount(renderDiagram);
</script>
<div bind:this={container} {@html svg}></div>
{#if error}
<div class="error">
<strong>Error:</strong> {error}
</div>
{/if}
<style>
.error {
color: red;
border: 1px solid red;
padding: 10px;
margin: 10px 0;
}
</style>
Webpack integration
Fromusage.md:227, Mermaid fully supports webpack:
// webpack.config.js
module.exports = {
// ... other config
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto'
}
]
}
};
In your application
import mermaid from 'mermaid';
mermaid.initialize({ startOnLoad: true });
// Or use programmatically
const element = document.querySelector('#diagram');
const definition = 'graph TD\nA-->B';
mermaid.render('uniqueId', definition).then(({ svg, bindFunctions }) => {
element.innerHTML = svg;
if (bindFunctions) {
bindFunctions(element);
}
});
Vite integration
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
optimizeDeps: {
include: ['mermaid']
}
});
Usage with Vite
import mermaid from 'mermaid';
mermaid.initialize({
startOnLoad: true,
theme: 'default'
});
Next.js integration
Client-side only component
// components/Mermaid.tsx
'use client';
import { useEffect, useRef, useState } from 'react';
interface MermaidProps {
chart: string;
}
export default function Mermaid({ chart }: MermaidProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [svg, setSvg] = useState('');
useEffect(() => {
// Import mermaid dynamically (client-side only)
import('mermaid').then((mermaid) => {
mermaid.default.initialize({ startOnLoad: false });
const uniqueId = `mermaid-${Date.now()}`;
mermaid.default.render(uniqueId, chart).then(({ svg, bindFunctions }) => {
setSvg(svg);
if (containerRef.current && bindFunctions) {
bindFunctions(containerRef.current);
}
});
});
}, [chart]);
return <div ref={containerRef} dangerouslySetInnerHTML={{ __html: svg }} />;
}
Usage in Next.js page
import dynamic from 'next/dynamic';
const Mermaid = dynamic(() => import('@/components/Mermaid'), {
ssr: false
});
export default function Page() {
const diagram = `
sequenceDiagram
Alice->>Bob: Hello
Bob->>Alice: Hi!
`;
return (
<div>
<h1>My Diagram</h1>
<Mermaid chart={diagram} />
</div>
);
}
Markdown renderers
With marked
Fromusage.md:303:
import { marked } from 'marked';
const renderer = new marked.Renderer();
renderer.code = function (code, language) {
if (code.match(/^sequenceDiagram/) || code.match(/^graph/)) {
return '<pre class="mermaid">' + code + '</pre>';
} else {
return '<pre><code>' + code + '</code></pre>';
}
};
marked.setOptions({ renderer });
With markdown-it
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt({
html: true
});
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const code = token.content.trim();
const info = token.info ? token.info.trim() : '';
if (info === 'mermaid') {
return `<pre class="mermaid">${code}</pre>`;
}
return self.renderToken(tokens, idx, options);
};
CDN usage
Fromusage.md:14:
<!doctype html>
<html lang="en">
<body>
<pre class="mermaid">
graph LR
A --- B
B-->C[fa:fa-ban forbidden]
B-->D(fa:fa-spinner);
</pre>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
</script>
</body>
</html>
Mermaid automatically renders diagrams with
class="mermaid" when startOnLoad is true (default). Set startOnLoad: false for manual control.Best practices
Initialize once
// Good - initialize once at app startup
mermaid.initialize({ startOnLoad: false, theme: 'default' });
// Bad - don't initialize on every render
function MyComponent() {
mermaid.initialize({ startOnLoad: false }); // ❌
// ...
}
Use unique IDs
Frommermaid.ts:155:
// Mermaid uses deterministic ID generation
const idGenerator = new utils.InitIDGenerator(
config.deterministicIds,
config.deterministicIDSeed
);
const id = `mermaid-${idGenerator.next()}`;
// In your code, generate unique IDs
const uniqueId = `diagram-${Date.now()}-${Math.random()}`;
await mermaid.render(uniqueId, definition);
Handle bindFunctions
Fromusage.md:279:
const { svg, bindFunctions } = await mermaid.render('id', definition);
element.innerHTML = svg;
// IMPORTANT: Call bindFunctions after inserting SVG into DOM
if (bindFunctions) {
bindFunctions(element);
}
Prevent re-rendering
Frommermaid.ts:165, Mermaid marks processed elements:
if (element.getAttribute('data-processed')) {
continue; // Skip already rendered diagrams
}
element.setAttribute('data-processed', 'true');
// Only re-render when diagram definition changes
useEffect(() => {
renderDiagram();
}, [diagramDefinition]); // ✓
// Not on every render
useEffect(() => {
renderDiagram();
}); // ❌