Skip to content

fix mermaid diagrams#855

Merged
tannerlinsley merged 1 commit intomainfrom
mermaid-fix
Apr 25, 2026
Merged

fix mermaid diagrams#855
tannerlinsley merged 1 commit intomainfrom
mermaid-fix

Conversation

@LadyBluenotes
Copy link
Copy Markdown
Member

@LadyBluenotes LadyBluenotes commented Apr 24, 2026

Summary by CodeRabbit

  • New Features
    • Added support for Mermaid diagram rendering in markdown code blocks, including dark mode support and copy functionality for diagram source code.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 24, 2026

Deploy Preview for tanstack ready!

Name Link
🔨 Latest commit a956640
🔍 Latest deploy log https://app.netlify.com/projects/tanstack/deploys/69eba9f26ffb060008c50a7d
😎 Deploy Preview https://deploy-preview-855--tanstack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 28 (🔴 down 21 from production)
Accessibility: 90 (no change from production)
Best Practices: 83 (🔴 down 9 from production)
SEO: 97 (no change from production)
PWA: 70 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

The pull request adds Mermaid diagram rendering support to markdown CodeBlocks. When a code block specifies lang='mermaid', it now renders as an interactive diagram instead of syntax-highlighted code. Both server and client components are updated to detect mermaid language and route to a new MermaidBlock component that handles dynamic mermaid library imports, dark mode detection, and SVG rendering.

Changes

Cohort / File(s) Summary
Server-side Mermaid Routing
src/components/markdown/CodeBlock.server.tsx
Detects lang === 'mermaid' and returns MermaidBlock component with presentation props; all other languages continue through existing renderCodeBlockDataCodeBlockView pipeline.
Client-side Mermaid Routing & Refactoring
src/components/markdown/CodeBlock.tsx
Refactored to detect lang === 'mermaid' and render MermaidBlock directly; non-mermaid code delegated to new internal HighlightedCodeBlock helper that retains render caching and async code fetching.
Mermaid Diagram Rendering
src/components/markdown/MermaidBlock.tsx
New client component that tracks dark mode via document.documentElement observation, dynamically imports mermaid library, manages render state machine (loadingrendered/error), and displays SVG diagrams with fallback CodeBlockView during loading.

Sequence Diagram

sequenceDiagram
    participant User
    participant CodeBlock
    participant MermaidBlock
    participant Mermaid as Mermaid Library
    participant DOM

    User->>CodeBlock: Render with lang='mermaid'
    CodeBlock->>CodeBlock: Detect mermaid language
    CodeBlock->>MermaidBlock: Route to MermaidBlock
    MermaidBlock->>MermaidBlock: Initialize dark mode tracking
    MermaidBlock->>DOM: Render placeholder CodeBlockView
    MermaidBlock->>Mermaid: Dynamic import
    MermaidBlock->>Mermaid: Initialize with theme (dark/default)
    Mermaid->>Mermaid: Render code to SVG
    MermaidBlock->>MermaidBlock: Update state with SVG
    MermaidBlock->>DOM: Replace placeholder with SVG diagram
    DOM->>User: Display interactive diagram
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 With mermaid and magic, the diagrams bloom,
Dark-themed and dashing through markdown's room,
From text into flow-charts, a diagram's delight,
The code blocks now shimmer with visual might! ✨🧜‍♀️

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'fix mermaid diagrams' is vague and generic, lacking specific details about what was fixed or how the implementation was changed. Provide a more descriptive title that clarifies the specific fix, such as 'Add MermaidBlock component for proper diagram rendering' or 'Refactor CodeBlock to handle mermaid diagrams separately'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mermaid-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/components/markdown/MermaidBlock.tsx (2)

61-65: Nit: useMemo here is unnecessary.

reactId from useId is already stable across renders of the same component instance, so mermaidId can be computed with a plain const (or inlined into the effect). Not a behavior issue — just dead ceremony.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/markdown/MermaidBlock.tsx` around lines 61 - 65, The mermaidId
is computed with React.useMemo unnecessarily; replace the React.useMemo call
with a plain constant computed from reactId (which comes from React.useId and is
stable) — e.g., compute mermaidId =
`mermaid-${reactId.replace(/[^a-zA-Z0-9_-]/g, '')}` directly in the MermaidBlock
component (or inline where used) and remove the useMemo import/usage to simplify
code.

26-43: Consider using useTheme() from ThemeProvider instead of implementing MutationObserver to detect theme changes.

ThemeProvider (lines 43–71) already owns and publishes the light/dark class state on documentElement via the exported useTheme hook. MermaidBlock's custom useIsDarkMode (lines 26–43) reimplements this by observing the same class mutations directly.

MutationObserver fires for every class change ThemeProvider makes — including transient toggles like adding theme-switching before updating to the final theme. Additionally, checking DOM state directly couples MermaidBlock to ThemeProvider's implementation detail.

Instead, replace useIsDarkMode with:

const { resolvedTheme } = useTheme()
const isDark = resolvedTheme === 'dark'

This is simpler, avoids DOM-coupling, and ensures MermaidBlock always sees the consistent theme state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/markdown/MermaidBlock.tsx` around lines 26 - 43, The custom
hook useIsDarkMode reimplements theme detection via a MutationObserver; replace
it by importing and using the ThemeProvider hook: call useTheme() (import from
ThemeProvider), derive const isDark = resolvedTheme === 'dark', remove the
MutationObserver-based useIsDarkMode function and any references to it, and
update MermaidBlock to consume the new isDark variable where needed so it relies
on ThemeProvider's resolvedTheme instead of DOM class mutations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/markdown/MermaidBlock.tsx`:
- Around line 90-117: The catch block inside the useEffect's renderMermaid flow
currently sets renderState to 'error' but neither logs the caught error nor
provides a distinct UI; update the catch to capture the error object, call
processLogger/error console (or existing logging utility) with the error and
context (e.g., mermaidId, code), call setRenderState({ status: 'error', error })
and then change the render branch that currently returns CodeBlockView when
renderState.status !== 'rendered' to distinguish 'loading' vs 'error' (e.g.,
when renderState.status === 'error' render CodeBlockView with an augmented title
like `${title ?? ''} (mermaid render failed)` or display a small inline error
message above the fallback) so parse failures are logged and visibly indicated
to authors; reference functions/identifiers: renderMermaid, setRenderState,
renderState, CodeBlockView, mermaidId, and code.

---

Nitpick comments:
In `@src/components/markdown/MermaidBlock.tsx`:
- Around line 61-65: The mermaidId is computed with React.useMemo unnecessarily;
replace the React.useMemo call with a plain constant computed from reactId
(which comes from React.useId and is stable) — e.g., compute mermaidId =
`mermaid-${reactId.replace(/[^a-zA-Z0-9_-]/g, '')}` directly in the MermaidBlock
component (or inline where used) and remove the useMemo import/usage to simplify
code.
- Around line 26-43: The custom hook useIsDarkMode reimplements theme detection
via a MutationObserver; replace it by importing and using the ThemeProvider
hook: call useTheme() (import from ThemeProvider), derive const isDark =
resolvedTheme === 'dark', remove the MutationObserver-based useIsDarkMode
function and any references to it, and update MermaidBlock to consume the new
isDark variable where needed so it relies on ThemeProvider's resolvedTheme
instead of DOM class mutations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3325a1eb-a2cc-4354-a6fd-0c74257a2a3b

📥 Commits

Reviewing files that changed from the base of the PR and between b3f2fb8 and a956640.

📒 Files selected for processing (3)
  • src/components/markdown/CodeBlock.server.tsx
  • src/components/markdown/CodeBlock.tsx
  • src/components/markdown/MermaidBlock.tsx

Comment on lines +90 to +117
} catch {
if (!cancelled) {
setRenderState({ status: 'error' })
}
}
}

void renderMermaid()

return () => {
cancelled = true
}
}, [code, isDark, mermaidId])

if (renderState.status !== 'rendered') {
return (
<CodeBlockView
className={className}
copyText={code.trimEnd()}
htmlMarkup={buildPlainCodeBlockHtml(code)}
isEmbedded={isEmbedded}
lang="mermaid"
showTypeCopyButton={showTypeCopyButton}
style={style}
title={title}
/>
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Error state is indistinguishable from the loading state and silently hides render failures.

On catch, renderState becomes 'error' but the UI renders the exact same CodeBlockView with the raw mermaid source as the 'loading' state does. A malformed diagram will therefore appear as a normal code block with no feedback that rendering failed — both to the user and to anyone debugging. At minimum, log the caught error (mermaid throws informative parse errors) and render a distinct error surface so authors can tell the difference.

🛠️ Suggested change
-      } catch {
+      } catch (error) {
         if (!cancelled) {
+          console.error('Failed to render mermaid diagram', error)
           setRenderState({ status: 'error' })
         }
       }

And branch the render so the error path is visible (e.g., render CodeBlockView with an added title like `${title ?? ''} (mermaid render failed)` or a small inline error message above the fallback).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/markdown/MermaidBlock.tsx` around lines 90 - 117, The catch
block inside the useEffect's renderMermaid flow currently sets renderState to
'error' but neither logs the caught error nor provides a distinct UI; update the
catch to capture the error object, call processLogger/error console (or existing
logging utility) with the error and context (e.g., mermaidId, code), call
setRenderState({ status: 'error', error }) and then change the render branch
that currently returns CodeBlockView when renderState.status !== 'rendered' to
distinguish 'loading' vs 'error' (e.g., when renderState.status === 'error'
render CodeBlockView with an augmented title like `${title ?? ''} (mermaid
render failed)` or display a small inline error message above the fallback) so
parse failures are logged and visibly indicated to authors; reference
functions/identifiers: renderMermaid, setRenderState, renderState,
CodeBlockView, mermaidId, and code.

@tannerlinsley tannerlinsley merged commit 180ddd3 into main Apr 25, 2026
8 checks passed
@tannerlinsley tannerlinsley deleted the mermaid-fix branch April 25, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants