Skip to content

Fixes wide Mermaid diagrams rendered with extremely small text due to responsive SVG sizing. #480

Open
aradhyacp wants to merge 6 commits intovercel:mainfrom
aradhyacp:fix/mermaid-diagram-view
Open

Fixes wide Mermaid diagrams rendered with extremely small text due to responsive SVG sizing. #480
aradhyacp wants to merge 6 commits intovercel:mainfrom
aradhyacp:fix/mermaid-diagram-view

Conversation

@aradhyacp
Copy link
Copy Markdown
Contributor

Description

This PR fixes an issue where wide Mermaid diagrams rendered with extremely small text due to SVG responsive scaling.

The solution introduces a two-layer approach:

  1. Normalize Mermaid SVGs to remove responsive sizing and enforce intrinsic dimensions.
  2. Add geometry-aware auto-fit logic in PanZoom to properly scale diagrams within the container.

This ensures diagrams are neither too small (unreadable) nor overly zoomed on initial render.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Refactoring (no functional changes)

Related Issues

Fixes #479
Closes #479
Related to #479

Changes Made

  • Added getMermaidSvgSize to extract intrinsic dimensions from SVG viewBox
  • Updated normalizeMermaidInlineSvg to remove responsive sizing and enforce fixed width/height
  • Enhanced PanZoom with:
    • contentSize for geometry-aware scaling
    • isAutoFit to enable automatic fitting
    • fitKey to trigger refit on diagram changes
  • Implemented auto-fit logic using both width and height constraints
  • Introduced baseZoom, effectiveMinZoom, and hasUserInteracted state for stable zoom behavior
  • Updated zoom clamping to support fit zoom below configured minZoom
  • Improved reset behavior to return to computed fit zoom instead of static initial zoom
  • Ensured auto-fit does not override user interaction
  • Added unit tests for SVG utilities (parsing + normalization)
  • Added PanZoom test to validate correct width+height fit calculation

Testing

  • All existing tests pass
  • Added new tests for the changes
  • Manually tested the changes

Test Coverage

Manually tested the Mermaid diagrams rendered

How I tested it locally:

I wanted to verify my changes, so I linked the local package into a test React app:

# In the streamdown repo
pnpm build
pnpm link

# In my test project
pnpm link streamdown

Then I used the following test component:

import React from 'react'
import { Streamdown } from 'streamdown';
import { mermaid } from '@streamdown/mermaid';


const App = () => {
  const markdown = `
  \`\`\`mermaid\nflowchart TD\n    classDef hypo    fill:#6A0DAD,color:#fff,stroke:#4a0080,stroke-width:3px,font-weight:bold\n    classDef ant     fill:#1565C0,color:#fff,stroke:#0D47A1,stroke-width:3px,font-weight:bold\n    classDef post    fill:#BF360C,color:#fff,stroke:#7f2000,stroke-width:3px,font-weight:bold\n    classDef antH    fill:#90CAF9,color:#0D1B2A,stroke:#1565C0,stroke-width:1.5px,font-weight:bold\n    classDef postH   fill:#FFAB91,color:#1a0000,stroke:#BF360C,stroke-width:1.5px,font-weight:bold\n    classDef target  fill:#E8F5E9,color:#1B5E20,stroke:#2E7D32,stroke-width:1.5px\n\n    HYP([\"HYPOTHALAMUS<br/>Master Neuroendocrine Regulator\"]):::hypo\n\n    HYP -->|\"Portal Blood System<br/>Releasing & Inhibiting<br/>Hormones\"| ANT\n\n    HYP -.->|\"Direct Neural Axons<br/>Supraoptic & Para-<br/>ventricular Nuclei\"| POST\n\n    subgraph ANTERIOR_LOBE[\"ANTERIOR PITUITARY (Adenohypophysis)\"]\n        ANT([\"ANTERIOR PITUITARY<br/>Tissue: Glandular Epithelium<br/>Origin: Rathke's Pouch<br/>SYNTHESIZES its own hormones\"]):::ant\n\n        GH([\"GH<br/>Growth Hormone\"]):::antH\n        TSH([\"TSH<br/>Thyroid-Stimulating Hormone\"]):::antH\n        ACTH([\"ACTH<br/>Adrenocorticotropic Hormone\"]):::antH\n        FSH([\"FSH<br/>Follicle-Stimulating Hormone\"]):::antH\n        LH([\"LH<br/>Luteinizing Hormone\"]):::antH\n        PRL([\"Prolactin<br/>PRL\"]):::antH\n    end\n\n    subgraph POSTERIOR_LOBE[\"POSTERIOR PITUITARY (Neurohypophysis)\"]\n        POST([\"POSTERIOR PITUITARY<br/>Tissue: Neural / Glial Pituicytes<br/>Origin: Downgrowth of Hypothalamus<br/>STORES & RELEASES only<br/>hormones made in hypothalamus\"]):::post\n\n        ADH([\"ADH / Vasopressin<br/>Antidiuretic Hormone\"]):::postH\n        OXY([\"Oxytocin<br/>OXT\"]):::postH\n    end\n\n    ANT --> GH & TSH & ACTH & FSH & LH & PRL\n    POST --> ADH & OXY\n\n    GH    --> TGH([\"Bones, Muscles, Liver<br/>Stimulates growth & IGF-1\"]):::target\n    TSH   --> TTSH([\"Thyroid Gland<br/>Releases T3 & T4, regulates metabolism\"]):::target\n    ACTH  --> TACTH([\"Adrenal Cortex<br/>Releases cortisol, stress response\"]):::target\n    FSH   --> TFSH([\"Gonads<br/>Follicle maturation / Spermatogenesis\"]):::target\n    LH    --> TLH([\"Gonads<br/>Ovulation / Testosterone production\"]):::target\n    PRL   --> TPRL([\"Mammary Glands<br/>Milk synthesis & secretion\"]):::target\n    ADH   --> TADH([\"Kidneys & Blood Vessels<br/>Water reabsorption, vasoconstriction\"]):::target\n    OXY   --> TOXY([\"Uterus & Mammary Glands<br/>Contractions, milk ejection, bonding\"]):::target\n\`\`\`
  `;

  return (
    <div className="App">
      <div className="mx-auto mt-5 w-200">
      <Streamdown plugins={{ mermaid }}>{markdown}</Streamdown>
      </div>
    </div>
  )
}

export default App

Screenshots/Demos

Before

image image

After

image image

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have created a changeset (pnpm changeset)

Changeset

  • I have created a changeset for these changes

Additional Notes

This fix intentionally separates content geometry (SVG intrinsic size) from viewport geometry (container size) and computes scaling explicitly rather than relying on browser responsiveness.

The approach resolves both failure modes:

  • Tiny text caused by responsive shrinking
  • Overly large diagrams on initial render

Auto-fit is applied only until user interaction to preserve user intent.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 26, 2026

@aradhyacp is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@aradhyacp aradhyacp changed the title Fixes an issue where wide Mermaid diagrams rendered with extremely small text due to responsive SVG sizing. Fixes wide Mermaid diagrams rendered with extremely small text due to responsive SVG sizing. Mar 26, 2026
@kenmueller
Copy link
Copy Markdown

Thank you!

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.

Wide mermaid diagrams are too short

2 participants