Problem
Streamdown is often embedded in micro-frontend setups: the markdown renderer runs inside a child app or isolated subtree of a larger shell, not as the only root on the page.
Those hosts frequently rely on:
- Scoped CSS — e.g. a wrapper class around the sub-app so design tokens and utilities apply only there.
- Prefixed Tailwind — e.g. Tailwind v4
prefix() or similar, so generated classes are tw:flex, tw:fixed, etc., and only match elements under the scanned scope.
Mermaid fullscreen is implemented with createPortal, typically to document.body. The fullscreen layer is then outside the micro-frontend’s DOM subtree. As a result:
- Prefixed / scoped utility classes from the host may not apply to nodes under
document.body, so layout, positioning, and fixed / z-index behavior can be wrong or missing.
- Stacking can break: the overlay may render under shell chrome (headers, footers, sidebars) that live in a different part of the tree with higher z-index.
This is the same portal vs in-tree class of issue as elsewhere in Streamdown (e.g. table fullscreen and DOM context — see #468 / PR #470).
Separately, #490 proposes host callbacks to replace download/fullscreen (e.g. desktop webviews). That addresses hosts that want to own the action. Many embedded apps instead need to keep the default fullscreen UI but have it mount inside their subtree so prefix + scope still apply.
Proposed solution
Add an optional, backward-compatible API to control where the Mermaid fullscreen portal mounts:
- Name (example):
fullscreenPortalContainer or mermaid.fullscreen.portalContainer
- Type:
HTMLElement | null or () => HTMLElement | null (match idioms you use elsewhere).
- Behavior: When set, Mermaid fullscreen (and any overlay that should share the same stacking context) portals into this element instead of
document.body.
- Default:
document.body — unchanged for existing consumers.
Docs: Short note for micro-frontends and prefixed / scoped Tailwind: provide a portal root element inside the same wrapper as <Streamdown /> and pass it here so fullscreen stays in the same DOM and CSS scope as the rest of the sub-app.
Alternatives considered
- Relying only on global CSS / safelist: Duplicates tokens, fights prefixing, and drifts from the shell’s theme.
- Replacing the entire Mermaid fence via a custom renderer: Too heavy for fixing portal placement alone.
Related issues
Contribution
Happy to help with a PR (API surface + tests) once maintainers agree on naming and placement on Streamdown vs the Mermaid plugin.
Pull request: #500
Problem
Streamdown is often embedded in micro-frontend setups: the markdown renderer runs inside a child app or isolated subtree of a larger shell, not as the only root on the page.
Those hosts frequently rely on:
prefix()or similar, so generated classes aretw:flex,tw:fixed, etc., and only match elements under the scanned scope.Mermaid fullscreen is implemented with
createPortal, typically todocument.body. The fullscreen layer is then outside the micro-frontend’s DOM subtree. As a result:document.body, so layout, positioning, andfixed/z-indexbehavior can be wrong or missing.This is the same portal vs in-tree class of issue as elsewhere in Streamdown (e.g. table fullscreen and DOM context — see #468 / PR #470).
Separately, #490 proposes host callbacks to replace download/fullscreen (e.g. desktop webviews). That addresses hosts that want to own the action. Many embedded apps instead need to keep the default fullscreen UI but have it mount inside their subtree so prefix + scope still apply.
Proposed solution
Add an optional, backward-compatible API to control where the Mermaid fullscreen portal mounts:
fullscreenPortalContainerormermaid.fullscreen.portalContainerHTMLElement | nullor() => HTMLElement | null(match idioms you use elsewhere).document.body.document.body— unchanged for existing consumers.Docs: Short note for micro-frontends and prefixed / scoped Tailwind: provide a portal root element inside the same wrapper as
<Streamdown />and pass it here so fullscreen stays in the same DOM and CSS scope as the rest of the sub-app.Alternatives considered
Related issues
Contribution
Happy to help with a PR (API surface + tests) once maintainers agree on naming and placement on
Streamdownvs the Mermaid plugin.Pull request: #500