Skip to content

feat(web): render mermaid fences as diagrams in chat - #8533

Closed
rishi-chauhan wants to merge 9 commits into
pingdotgg:mainfrom
rishi-chauhan:feat/web-mermaid-chat-diagrams
Closed

feat(web): render mermaid fences as diagrams in chat#8533
rishi-chauhan wants to merge 9 commits into
pingdotgg:mainfrom
rishi-chauhan:feat/web-mermaid-chat-diagrams

Conversation

@rishi-chauhan

@rishi-chauhan rishi-chauhan commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

This change is to support Cursor cli. Cursor cli and its models generate mermaid flowcharts frequently. Now that t3code is planning to support Cursor cli, it PR would help.

Chat markdown now renders mermaid and mmd fences as diagrams instead of highlighted source.

  • After a message finishes streaming, those fences draw as SVG in the existing code-block chrome.
  • Copy still copies the mermaid source. A toolbar toggle switches between diagram and source.
  • Parse failures fall back to the highlighted fence plus a short error.
  • The mermaid library is loaded with a dynamic import only when a mermaid fence is present, so ordinary chats do not pay for it.
  • Collapsed plan previews no longer cut a started fence in half. If a mermaid block has begun, the preview keeps reading until the fence closes, then truncates. The card still CSS-clips height.

Desktop inherits this through the web UI. Mobile is unchanged.

Why

Agents already emit mermaid flowcharts in replies and plans. T3 only syntax-highlighted that text, so users had to copy it into another tool to see the picture. Rendering in place is the obvious chat behavior.

The collapsed-plan path used a line budget that could split an opening mermaid fence from its closing marker. Mermaid then parsed a fragment and threw (for example got '1'). Completing the fence avoids that without hiding a plan that starts with a diagram.

UI Changes

  • Mermaid fences in chat, plans, file-preview markdown, and PR markdown show a diagram by default once streaming ends.
  • Code-block header: Show source / Show diagram, plus the existing copy action.
  • Collapsed plans can show a complete mermaid diagram at the top of the preview; extra plan text is still behind Expand plan.

Collapsed plan view:
image

In chat:
image

Test plan

  • In chat, a completed mermaid flowchart renders as SVG; copy pastes the source.
  • Toggle Show source / Show diagram on that block.
  • While the assistant is still streaming the fence, it stays as highlighted source.
  • Invalid mermaid falls back to source plus an error, not a retry loop.
  • Collapse a long plan that contains a mermaid diagram (including one that starts the plan). The diagram still renders; expand shows the rest of the plan.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Render mermaid fences as diagrams in chat messages

  • Adds a MermaidDiagram component and mermaidRenderer utility that asynchronously renders mermaid/mmd code fences into cached, theme-aware SVGs with unique ids per insertion
  • MarkdownCodeBlock in ChatMarkdown.tsx shows a diagram/source toggle (EyeIcon/Code2Icon) for mermaid fences when the message is not streaming; during streaming, fences stay as source code. Render failures fall back to source view with an inline error alert
  • Clipboard logic in markdown-clipboard.ts now copies the original mermaid fence (escaped pre/code) instead of rendered SVG, even when the selection originates from inside the SVG
  • buildCollapsedProposedPlanPreviewMarkdown in proposedPlan.ts tracks open fenced blocks so previews no longer truncate mid-fence; unclosed fences are dropped with an overflow marker
  • Behavioral Change: adds mermaid (^11.17.2) as a new dependency to apps/web; dynamically imported on first render so bundle size impact is deferred to runtime

Macroscope summarized f2ab071.


Note

Medium Risk
Rendered SVG is injected via dangerouslySetInnerHTML; risk is mitigated by mermaid strict mode but this is still untrusted assistant content in the DOM. Adds a sizable client dependency loaded on first mermaid fence.

Overview
Chat markdown now renders mermaid / mmd code fences as inline SVG diagrams once a message finishes streaming, instead of only Shiki-highlighted source. While streaming, fences stay as normal code blocks so partial diagrams are not parsed.

ChatMarkdown wires this through existing code-block chrome: a Show source / Show diagram toggle, copy still uses the raw fence text, and parse failures show an alert and fall back to highlighted source. Rendering is delegated to a new MermaidDiagram component backed by renderMermaidSvg (dynamic import("mermaid"), per-theme init with securityLevel: "strict", LRU-cached SVGs with fresh DOM ids on reuse).

Copy/paste is updated so selecting a rendered diagram copies the original fenced mermaid source (plain and HTML), including when the selection is inside the SVG or spans surrounding prose.

Collapsed plan previews (buildCollapsedProposedPlanPreviewMarkdown) now track open markdown fences so truncation does not split a mermaid/code block mid-fence; unclosed fences are dropped rather than swallowing the rest of the plan.

Reviewed by Cursor Bugbot for commit f2ab071. Bugbot is set up for automated code reviews on this repo. Configure here.

Agents often emit mermaid flowcharts as fenced code. Those blocks were
only syntax-highlighted, so users had to copy them out of T3 to see a
diagram.

Render mermaid and mmd fences as SVG after a message finishes streaming,
keep copy on the source, and offer a toggle back to the highlighted
fence. Load mermaid only when a fence appears so ordinary chats do not
pay for the library.

Collapsed plan previews keep a started fence intact through its closing
marker so a truncated mermaid block is not parsed as a broken diagram.
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 38c89a0b-23f9-44b6-bb7c-1c0d9d10ff4e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 28, 2026
Comment thread apps/web/src/proposedPlan.ts
Comment thread apps/web/src/proposedPlan.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the mermaid chat-diagram changes against the shared chat-markdown chrome. Three concrete issues on the new rendering surface: a dead max-width override that defeats the diagram's own scroll container, prose margins leaking into the code-block chrome from the new <p> placeholders, and an unstyled horizontal scrollbar next to the styled pre scrollbar. Everything else (primitive reuse for the toggle, clipboard contract, streaming gate) looks consistent.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/MermaidDiagram.tsx
Comment thread apps/web/src/components/ChatMarkdown.tsx
Comment thread apps/web/src/components/chat/MermaidDiagram.tsx
Comment thread apps/web/src/index.css
@rishi-chauhan
rishi-chauhan marked this pull request as ready for review August 28, 2026 13:28
Comment thread apps/web/src/components/chat/MermaidDiagram.tsx
Comment thread apps/web/src/proposedPlan.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a substantial user-facing feature that adds Mermaid rendering and changes completed fences, clipboard behavior, and collapsed plan previews across shared markdown surfaces. Rendering is enabled by default for existing mermaid/mmd fences, so the production behavior warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Review found truncated quoted/indented fences, empty copy from inside
the SVG, prose margins on placeholder paragraphs, an unstyled
horizontal scrollbar, and mermaid's inline max-width beating our CSS.

Complete fences after blockquote and list prefixes, drop a fence that
never closes, restore mermaid source from the diagram wrapper on copy,
and match the existing chat-markdown scrollbar and diagram sizing.
Comment thread apps/web/src/markdown-clipboard.ts

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the new mermaid clipboard-restore branches in markdown-clipboard.ts are unreachable from the only production caller, so selecting inside a rendered diagram still copies SVG label text. The earlier findings (prose-margin leak on the placeholder/error rows, missing .chat-markdown scrollbar treatment on the diagram scroll container, and the max-width override) all look addressed.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/markdown-clipboard.ts
Comment thread apps/web/src/markdown-clipboard.ts
chatMarkdownClipboardPayload serializes a detached cloneContents()
tree, so closest() cannot reach the diagram wrapper. Resolve
data-markdown-copy from the live common ancestor instead.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the mermaid clipboard path. The earlier live-ancestor fix looks right for text/plain; the text/html flavor for the same selection now ends up empty.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/markdown-clipboard.ts Outdated
Selecting inside a rendered diagram strips the svg from text/html, so
rich-paste targets insert nothing. Put the mermaid fence in a pre/code
block instead, matching how those fences copied before diagrams.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two consistency/regression findings in the new mermaid rendering path. Everything flagged in earlier runs (prose-margin leaks, scrollbar treatment, dead clipboard branches, empty HTML flavor for diagram-only selections) looks addressed.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/markdown-clipboard.ts
Comment thread apps/web/src/index.css
A whole-message copy skipped the diagram-only clipboard branch and
stripped the svg, so rich-paste dropped the fence. Replace mermaid
hosts with a pre/code block before sanitizing.

Drop the svg max-width !important override so types that still use
mermaid's default useMaxWidth stay fit-to-width instead of stretching.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding on the new mermaid renderer: failed renders leave mermaid's temporary error-diagram element attached to document.body.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/lib/mermaidRenderer.ts
Failed mermaid.render() draws a syntax-error diagram in a unique temp node
and throws before cleanup. suppressErrorRendering lets mermaid remove that
node and reject, which MermaidDiagram already surfaces as an error.
Comment thread apps/web/src/lib/mermaidRenderer.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: rendered mermaid SVGs are not cached across remounts, so every scroll-back in the virtualized message feed replays the async render (placeholder flash + height jump). Details inline.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/MermaidDiagram.tsx Outdated
Virtualized chat remounts replay mermaid.render and flash the loading
placeholder. Cache successful svgs like highlighted code, and clear a
rejected dynamic import so a later render can load the chunk.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1c53982. Configure here.

Comment thread apps/web/src/lib/mermaidRenderer.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the mermaid chat-diagram changes for UI consistency. The earlier findings (render cache, suppressErrorRendering, useMaxWidth handling instead of a max-width: none !important override, mermaid-aware clipboard HTML, non-<p> placeholders, shared code-block scrollbar treatment) are addressed. One residual layout-stability issue remains on theme switching.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/MermaidDiagram.tsx Outdated
Cached svg markup reused mermaid's t3mermaid ids, so a second visible
copy of the same fence could steal markers via url(#…). Clone those ids
on each cache read. Keep the last svg while a theme re-render is in
flight, and remount on fence content change so the placeholder is only
for new diagrams.
@lmdevv

lmdevv commented Sep 1, 2026

Copy link
Copy Markdown

this would be a crazy good feature, commenting for support !

@ekrako

ekrako commented Sep 3, 2026

Copy link
Copy Markdown

+1 on this. Mermaid diagrams show up constantly in agent output (Cursor, Claude Code, Codex all emit them), and rendering them inline instead of as raw source is a big readability win for the chat view.

@t3dotgg @juliusmarminge any chance this can get a look? Would love to see mermaid rendering land.

@shivamhwp

Copy link
Copy Markdown
Collaborator

Note: GPT-5.6 on behalf of shivam (@shivamhwp).

Thanks for the work on this, including the caching, source toggle, and follow-up fixes. We are not planning to add Mermaid rendering to T3 Code right now.

Even with lazy loading and caching, Mermaid adds a large frontend dependency and moves diagram parsing, graph layout, SVG generation, and DOM work onto the client. That creates performance and memory risks in long, virtualized conversations. The benefit does not justify that cost for us right now, especially while mobile would still render the same content differently.

We are closing this based on product direction. This is not a request to revise the implementation.

@shivamhwp shivamhwp closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants