Elements

Elements · Renderers

Mermaid diagram

Mermaid diagrams rendered inside messages, including partial streaming input.

Yes No Start Is it working? Great! Debug
fig. 01

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 init

Then 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.

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

components/assistant-ui/elements/markdown-text.tsx
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.

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

SelectorTypeDescription
s.optional.part?.status.type === "running"booleanRead 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

PropTypeDefaultDescription
codestringrequiredMermaid 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.
streamingbooleanfalseShows the skeleton instead of parsing while true.
classNamestringMerged onto whichever state is showing.

MermaidZoom

PropTypeDefaultDescription
svgstringrequiredThe 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.
childrenReactNoderequiredThe inline content, rendered as-is alongside the expand trigger.