Problem
In the web UI, mermaid diagrams with long labels (very common with CJK text, ~12+ Chinese characters) render with the label text overflowing its node box on both sides, and adjacent nodes' labels overlap each other:
The node rect is sized for the wrapped label, but the text renders as one long single line centered on the node.
Root cause
- mermaid (11.15,
securityLevel: loose → htmlLabels on) wraps long labels via CSS soft wrap inside a <foreignObject> (max-width: 200px, no <br> in the DOM) and sizes the node rect from the wrapped measurement (~200px + padding).
- Before inserting the SVG, markstream-vue runs it through stream-markdown-parser's
toSafeSvgElement, whose replaceForeignObjectLabels replaces every <foreignObject> with a single-line SVG <text> — it only splits lines on literal <br>, so the CSS soft-wrap structure is lost.
- The full-width single-line text is then rendered centered (
text-anchor="middle") on a rect sized for 200px → symmetric overflow on both sides; dagre laid the nodes out for the small measured width, so neighbors' labels overlap.
Measured with the same dependency versions (mermaid 11.15.0 + stream-markdown-parser 1.1.7): a 35-char CJK label yields a 260px node rect but 576px of rendered text (~158px overflow per side).
Notes
- App-side CSS is not the cause: after sanitization there is no
foreignObject left in the DOM for any selector to reach, and mermaid injects its own font styles into the SVG before measuring.
- A fix PR is on the way: it injects
%%{init: {"htmlLabels": false}}%% into mermaid fences so mermaid lays out native SVG text with real width-based line breaking, leaving the sanitizer nothing to flatten. (flowchart.htmlLabels is deprecated and silently shadowed by the global default in mermaid 11.15 — only the global key actually takes effect.)
Environment
- kimi-web (web UI) with markstream-vue 1.0.9-beta.1, stream-markdown-parser 1.1.7, mermaid 11.15.0
- Reproduces in Chrome; mechanism is platform-independent.
Problem
In the web UI, mermaid diagrams with long labels (very common with CJK text, ~12+ Chinese characters) render with the label text overflowing its node box on both sides, and adjacent nodes' labels overlap each other:
The node rect is sized for the wrapped label, but the text renders as one long single line centered on the node.
Root cause
securityLevel: loose→ htmlLabels on) wraps long labels via CSS soft wrap inside a<foreignObject>(max-width: 200px, no<br>in the DOM) and sizes the node rect from the wrapped measurement (~200px + padding).toSafeSvgElement, whosereplaceForeignObjectLabelsreplaces every<foreignObject>with a single-line SVG<text>— it only splits lines on literal<br>, so the CSS soft-wrap structure is lost.text-anchor="middle") on a rect sized for 200px → symmetric overflow on both sides; dagre laid the nodes out for the small measured width, so neighbors' labels overlap.Measured with the same dependency versions (mermaid 11.15.0 + stream-markdown-parser 1.1.7): a 35-char CJK label yields a 260px node rect but 576px of rendered text (~158px overflow per side).
Notes
foreignObjectleft in the DOM for any selector to reach, and mermaid injects its own font styles into the SVG before measuring.%%{init: {"htmlLabels": false}}%%into mermaid fences so mermaid lays out native SVG text with real width-based line breaking, leaving the sanitizer nothing to flatten. (flowchart.htmlLabelsis deprecated and silently shadowed by the global default in mermaid 11.15 — only the global key actually takes effect.)Environment