Skip to content

Fix clipped mermaid node labels by pinning label line-height#149

Merged
HamptonMakes merged 1 commit into
block:mainfrom
mritterhoff:mermaid-label-line-height
Jul 17, 2026
Merged

Fix clipped mermaid node labels by pinning label line-height#149
HamptonMakes merged 1 commit into
block:mainfrom
mritterhoff:mermaid-label-line-height

Conversation

@mritterhoff

Copy link
Copy Markdown
Contributor

Problem

On plan pages, any mermaid flowchart node label that wraps to a second line gets cut off by the bottom of its node box. The same diagram source renders fine in mermaid-cli and other renderers.

Root cause

The page stylesheet sets line-height: 1.6 on body. Mermaid renders node labels as HTML inside SVG <foreignObject> elements, so that page-level line-height cascades into them — but mermaid sizes node boxes assuming its own default label line-height (~1.2). Wrapped labels end up ~40% taller than the box mermaid measured for them, and the overflow is clipped. Because it's a geometry mismatch between page CSS and mermaid's layout measurement, diagram-side knobs (font size, padding, node spacing) can't fix it.

Fix

Pin line-height: 1.2 on label elements inside foreignObject within rendered diagrams, scoped under .markdown-rendered .mermaid-diagram, so displayed text matches the geometry mermaid laid out. This fixes every existing and future diagram without authors needing a per-diagram %%{init: ...}%% workaround.

Verification

Built a replica of CoPlan's renderer — this repo's application.css + the mermaid_controller.js config (mermaid 11.16.0 from jsdelivr, securityLevel: "strict", same initialize call) — in headless Chrome, rendering a flowchart with wrapping labels. Before the change, the last line of every wrapped node label and edge label is clipped; after, all lines render fully. Screenshots in the comment below.

Validation References

  • Mermaid renders flowchart labels as HTML in foreignObject by default (htmlLabels): https://mermaid.js.org/config/schema-docs/config.html
  • CoPlan's mermaid render path: engine/app/javascript/controllers/coplan/mermaid_controller.js (renders via mermaid.render, inserts SVG into .mermaid-diagram)
  • Page line-height: 1.6 that leaks in: engine/app/assets/stylesheets/coplan/application.css (body rule)
  • Alternatives tried in the replica: htmlLabels: false still clipped; a display: table-cell override made some wrapped lines disappear entirely; per-diagram %%{init: {"themeCSS": ...}}%% works but requires every author to know the workaround.

🤖 Generated with Claude Code

The page-level line-height (1.6) cascades into the HTML labels mermaid
renders inside SVG foreignObject elements, but mermaid sizes node boxes
assuming its own default label line-height (~1.2). Any label that wraps
ends up taller than its box and the overflow is clipped.

Pin line-height back to 1.2 on foreignObject label elements inside
mermaid diagrams so rendered text matches the geometry mermaid measured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mritterhoff

Copy link
Copy Markdown
Contributor Author

🤖 Verification screenshots (replica renderer, headless Chrome — same stylesheet + mermaid 11.16.0 config as this repo):

Before — last line of every wrapped label clipped:

Before: wrapped node labels clipped

After — all label lines render fully:

After: labels render fully

@HamptonMakes
HamptonMakes merged commit 31fabc3 into block:main Jul 17, 2026
3 of 4 checks passed
HamptonMakes added a commit that referenced this pull request Jul 20, 2026
…resh

Prefer this branch's visibility model while genuinely adopting main's new
features:

- LinkPreviews/Slack unfurls (#154): adopted; context now speaks the
  visibility language — Private/Archived flagged, published unmarked,
  never "Draft". plan_og_description delegates to the same builder.
- Mermaid comment anchors (#148/#149/#151): adopted; mermaid-settled
  re-highlighting wired into our no-tabs plan page, anchors-updated
  re-anchoring wired into our headless comment nav. Clicking a comment
  mark inside a diagram now opens its thread popover instead of the
  lightbox (showModal force-hides popovers).
- Landing refresh + agent-instructions view (#140): adopted; step copy
  and mock badge updated to the born-published model (type badge, no
  status badge).
- Status badge menu (#146): superseded — visibility is the only state,
  toggled by the header eye; status_menu_controller removed.
- Attachments dropzone (#147): superseded by our add-modal dropzone;
  spec selectors reconciled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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