Rendering Mermaid diagrams in Next.js requires client-side dynamic import
I tried calling mermaid in a Server Component to generate SVG strings at build time. Predictably, mermaid uses DOM APIs like getBBox internally, so it fails on the server.
The solution is a client component with dynamic import inside useEffect. This keeps mermaid out of the initial bundle. The other key detail: use resolvedTheme from next-themes (not theme) in the dependency array so diagrams re-render on theme toggle.
"use client";
import { useEffect, useRef, useState } from "react";
import { useTheme } from "next-themes";
export function Mermaid({ chart }: { chart: string }) {
const containerRef = useRef<HTMLDivElement>(null);
const [svg, setSvg] = useState("");
const { resolvedTheme } = useTheme();
useEffect(() => {
let cancelled = false;
async function render() {
const mermaid = (await import("mermaid")).default;
mermaid.initialize({
startOnLoad: false,
theme: resolvedTheme === "dark" ? "dark" : "default",
});
const { svg } = await mermaid.render(
`mermaid-${Math.random().toString(36).slice(2, 9)}`,
chart,
);
if (!cancelled) setSvg(svg);
}
render();
return () => { cancelled = true; };
}, [chart, resolvedTheme]);
return <div ref={containerRef} dangerouslySetInnerHTML={{ __html: svg }} />;
}resolvedTheme returns the actual theme ("light" or "dark") even when the user has "system" selected. Using theme directly would give you "system", which isn't useful for picking a mermaid theme.
