Skip to content

feat(desktop): render Mermaid diagrams in markdown file preview - #40531

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:feat/desktop-mermaid-preview
Closed

feat(desktop): render Mermaid diagrams in markdown file preview#40531
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:feat/desktop-mermaid-preview

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

Summary

Render Mermaid diagrams in the Desktop markdown file preview. Fenced code blocks with language mermaid are now rendered as interactive SVG diagrams instead of showing raw source text.

Fixes #38654

Root Cause

The custom MarkdownCode component override in preview-file.tsx routes all fenced code blocks through ShikiHighlighter, bypassing Streamdown's internal mermaid plugin dispatch. Even if @streamdown/mermaid were wired as a plugin, the custom components.code would intercept before the plugin could fire.

Solution

Detect language === 'mermaid' inside MarkdownCode and delegate to a lazy-loaded MermaidBlock component that calls mermaid.render() with securityLevel: 'strict'. The mermaid library is code-split via React.lazy so it only loads when a mermaid block is actually encountered.

Changes

File Change
apps/desktop/package.json Add mermaid ^11.15.0 dependency
apps/desktop/src/components/chat/mermaid-block.tsx New MermaidBlock component
apps/desktop/src/app/chat/right-rail/preview-file.tsx Mermaid detection in MarkdownCode

Implementation Details

  • Lazy loading: MermaidBlock is loaded via React.lazy() — the ~2MB mermaid library is only fetched when a user opens a file containing mermaid blocks
  • Security: mermaid.render() uses securityLevel: 'strict' which strips <script> tags and event handlers from generated SVG
  • Error handling: Render errors show a collapsible error message with the raw source for debugging
  • Dark mode: Mermaid theme adapts to the current dark/light mode via document.documentElement.classList.contains('dark')
  • Zero impact on non-mermaid files: The new code path only activates for language === 'mermaid' — all other fenced blocks continue through ShikiHighlighter as before

Testing

  1. Create a .md file with a mermaid block:
    ```mermaid
    graph TD
        A[Start] --> B{Decision}
        B -->|Yes| C[OK]
        B -->|No| D[End]
    ```
  2. Open the file in Desktop right-rail preview
  3. Verify the diagram renders as an SVG (not raw text)
  4. Verify dark/light mode switching updates the diagram theme
  5. Verify malformed mermaid source shows an error with collapsible source view

When previewing .md files in the right-rail, fenced code blocks with
language 'mermaid' are now rendered as SVG diagrams instead of showing
raw source text.

Root cause: the custom MarkdownCode component override in preview-file.tsx
routes ALL fenced blocks through ShikiHighlighter, bypassing Streamdown's
internal mermaid plugin dispatch. Even if @streamdown/mermaid were wired
as a plugin, the custom components.code would intercept before the plugin
could fire.

Fix: detect language === 'mermaid' in MarkdownCode and delegate to a
lazy-loaded MermaidBlock component that calls mermaid.render() with
securityLevel 'strict'. The mermaid library is code-split via React.lazy
so it only loads when a mermaid block is actually encountered.

Changes:
- apps/desktop/package.json: add mermaid ^11.15.0 dependency
- apps/desktop/src/components/chat/mermaid-block.tsx: new component
- apps/desktop/src/app/chat/right-rail/preview-file.tsx: mermaid detection

Fixes NousResearch#38654
@liuhao1024
liuhao1024 requested a review from a team June 6, 2026 14:19
@Morad37

Morad37 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Nice to see this land. The file preview is the right place to start — securityLevel: 'strict' and lazy importing mermaid avoid the main bundle bloat.

Related: #40493 is about getting the same rendering in the chat assistant responses (the markdown-text.tsx component in the chat surface, not the file preview). The MermaidBlock component you built here could be reused there with the same Suspense wrapper once the chat stream finishes.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have labels Jun 6, 2026

@alpindiay alpindiay left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PR #40531 Review -- Mermaid diagram rendering in markdown preview

Summary: Clean feature implementation that adds Mermaid diagram rendering to the file preview pane. Good use of lazy loading and Suspense.

What Changed

  • New dependency: mermaid@^11.15.0 added to apps/desktop/package.json
  • Preview file integration (preview-file.tsx): Detects language === 'mermaid' in fenced code blocks and renders via lazy-loaded MermaidBlock component wrapped in Suspense.
  • New component (mermaid-block.tsx): 84-line component handling three states -- loading spinner, error display (with source toggle), and rendered SVG.

Findings

Severity Category Details
PASS Security Mermaid initialized with securityLevel: 'strict' -- prevents XSS via malicious diagram markup. dangerouslySetInnerHTML is used for the rendered SVG, but strict mode sanitizes output, making this safe.
PASS Correctness Clean-up via cancelled flag pattern in useEffect is correct. Singleton loadMermaid() avoids duplicate imports. Proper error boundary with try/catch.
MEDIUM Tests No tests added. The MermaidBlock component has multiple states (loading, error, rendered) and async rendering logic. A basic smoke test (e.g., renders a valid chart, shows error on invalid syntax) would significantly improve confidence.
PASS Performance lazy() + Suspense means the large mermaid library is only loaded when a mermaid code block is actually encountered. Good code-splitting.
INFO Style Math.random().toString(36).slice(2, 10) for generating element IDs is technically not collision-proof but is fine for per-render unique IDs. No practical issue.

Verdict: APPROVE with suggestion

The implementation is solid. I would strongly recommend adding a basic test file for mermaid-block.tsx in a follow-up PR, covering at minimum:

  • Renders a simple valid mermaid chart (flowchart/graph)
  • Displays error state on invalid syntax
  • Cleanup on unmount

No blocking issues -- this is good to merge.

@teknium1

teknium1 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Salvaged into #40630 with your authorship credited (Co-authored-by). Re-verified on current main, tightened, tested. Thanks!

#40630

@teknium1 teknium1 closed this Jun 6, 2026
teknium1 added a commit that referenced this pull request Jul 6, 2026
Salvaged from #40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Jul 7, 2026
Salvaged from #40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
teknium1 added a commit that referenced this pull request Jul 7, 2026
Salvaged from #40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
@teknium1

teknium1 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Merged via #40630 — thanks @liuhao1024 for the original implementation in this PR; your commit is preserved (rebase-merge) with a follow-up that routes the preview pane through the shared embeds registry that landed in #52935.

santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Salvaged from NousResearch#40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
justemu pushed a commit to justemu/hermes-agent that referenced this pull request Jul 18, 2026
Salvaged from NousResearch#40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Salvaged from NousResearch#40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
Salvaged from NousResearch#40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Salvaged from NousResearch#40531; surgically reapplied onto current main (i18n'd
preview-file.tsx). mermaid dep already present on main.

Co-authored-by: liuhao1024 <liuhao1024@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Markdown file preview does not render Mermaid diagrams in Desktop

5 participants