Elements · Renderers
Mermaid diagram
Mermaid diagrams rendered inside messages, including partial streaming input.
Installation
npx shadcn@latest add "@assistant-ui/mermaid-diagram"First time? Set up a runtime
Runtime components read their state from an assistant-ui runtime. Add one to an existing project:
npx assistant-ui@latest initThen wrap your app in a runtime provider:
import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";
export default function App() {
const runtime = useChatRuntime({
transport: new AssistantChatTransport({ api: "/api/chat" }),
});
return (
<AssistantRuntimeProvider runtime={runtime}>
{/* your components */}
</AssistantRuntimeProvider>
);
}The installation guide covers new projects, templates, and API routes.
npx shadcn@latest add "@assistant-ui/elements-mermaid-diagram"Props-driven: no runtime or provider required.
MermaidDiagram renders a fenced mermaid code block as an SVG diagram, with a skeleton while the source is still streaming and a raw-source fallback if it fails to parse. With a runtime it derives the streaming flag from the active message part; standalone you pass streaming yourself.
Getting started
The kit wraps the base diagram and reads whether the current message part is still running, so the model can keep emitting mermaid syntax without a half-drawn diagram flashing on every token.
Add it to markdown-text's language overrides
import { MermaidDiagram } from "@/components/assistant-ui/elements/mermaid-diagram.aui";
const MarkdownTextImpl = () => {
return (
<MarkdownTextPrimitive
remarkPlugins={[remarkGfm]}
className="aui-md"
components={defaultComponents}
componentsByLanguage={{
mermaid: { SyntaxHighlighter: MermaidDiagram },
}}
/>
);
};A fenced mermaid code block in an assistant message now renders as a diagram instead of as code.
Standalone, you own the streaming flag yourself.
Render a diagram with a controlled streaming flag
import { MermaidDiagram } from "@/components/assistant-ui/elements/mermaid-diagram";
<MermaidDiagram code={code} streaming={isStreaming} />;While streaming is true it shows a skeleton instead of parsing; set it to false once the Mermaid source is complete.
Anatomy
// streaming
<div data-slot="mermaid-skeleton" aria-label="Rendering diagram" />
// parsed
<div data-slot="mermaid-zoom-wrap">
<div data-slot="mermaid-diagram" />
<button data-slot="mermaid-zoom-trigger" aria-label="Expand diagram" />
</div>
// unparseable
<div data-slot="mermaid-fallback">
<pre>{/* raw mermaid source */}</pre>
<p>diagram could not be rendered</p>
</div>Rendering is synchronous: the diagram is built from code with useMemo, so a parse error is caught in the same pass rather than surfacing as a thrown render error. The colors passed to the renderer (bg, fg, muted, border, accent) are CSS variables (--background, --foreground, and so on), so a diagram matches the active theme automatically. The zoom trigger appears on hover (or on focus) and opens a full-screen overlay: scroll to zoom between 0.5x and 4x centered on the pointer, drag to pan, +/-/reset/close buttons, Escape to close, and a focus trap while it is open.
Examples
Wrap a diagram you already rendered
MermaidDiagram.Zoom (also exported as MermaidZoom) is the pan-and-zoom chrome on its own. Wrap any pre-rendered SVG in it to get the same expand button and lightbox, without going through Mermaid parsing:
import { MermaidZoom } from "@/components/assistant-ui/elements/mermaid-diagram";
<MermaidZoom svg={mySvgString}>
<div dangerouslySetInnerHTML={{ __html: mySvgString }} />
</MermaidZoom>;Restyle the frame
Both lanes take className on the root, applied to whichever of the three states (skeleton, diagram, fallback) is currently showing.
<MermaidDiagram className="rounded-none" code={code} />API reference
Message part state
| Selector | Type | Description |
|---|---|---|
s.optional.part?.status.type === "running" | boolean | Read with useAuiState. Forwarded as streaming. true while the current message part exists and is running. |
node, components, and language (react-markdown's code-block wrapper props) are accepted for type compatibility with MarkdownText's componentsByLanguage slot and otherwise unused.
MermaidDiagram
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | required | Mermaid source. Supports flowcharts, sequence, class, state, and entity-relationship diagrams, and XY charts (bar, line, or combined); other diagram types fall back to the raw-source view. |
streaming | boolean | false | Shows the skeleton instead of parsing while true. |
className | string | Merged onto whichever state is showing. |
MermaidZoom
| Prop | Type | Default | Description |
|---|---|---|---|
svg | string | required | The SVG markup to show in the zoomed overlay. Its id attributes and internal references are rewritten so the overlay copy never collides with the inline one. |
children | ReactNode | required | The inline content, rendered as-is alongside the expand trigger. |
Pass streaming yourself, as in the standalone step above; every other prop behaves identically to the runtime lane.