Skip to content

MermaidBlockNode (Component)

MermaidBlockNode is a lightweight, extensible renderer for Mermaid diagrams intended for embedding interactive Mermaid charts within documents. The component supports progressive rendering, source/preview toggling, copying source, exporting SVG, and a pseudo-fullscreen modal (with zoom and drag).

Props (key)

  • node: any — the Mermaid code node (required)
  • isDark?: boolean — dark mode flag
  • loading?: boolean — initial loading placeholder
  • maxHeight?: string | null — maximum height
  • isStrict?: boolean — run Mermaid in securityLevel: 'strict' with DOMPurify + HTML-label hardening; use this when rendering untrusted diagrams to strip inline scripts/javascript: URLs that could otherwise leak into the SVG
  • onRenderError?: (error: unknown, code: string, container: HTMLElement) => boolean | void — custom error handler called when mermaid rendering fails. Return true to prevent the default error display. Receives the error, the raw mermaid source code, and the container DOM element so you can render custom content.
  • Header / control props (all optional, default true):
    • showHeader, showModeToggle, showCopyButton, showExportButton, showFullscreenButton, showCollapseButton, showZoomControls, showTooltips
  • enableWheelZoom?: boolean — enable Ctrl/Cmd + wheel zoom in the canvas (default false)
  • Timeouts (ms): workerTimeoutMs, parseTimeoutMs, renderTimeoutMs, fullRenderTimeoutMs (defaults: 1400/1800/2500/4000)
  • Streaming tuning: renderDebounceMs, contentStableDelayMs, previewPollDelayMs, previewPollMaxDelayMs, previewPollMaxAttempts

Slots

  • header-left — replace the left area (defaults to Mermaid icon + label)
  • header-center — replace the center area (defaults to preview/source toggle)
  • header-right — replace the right-side action buttons (take full control of the default controls)

Emits

The component emits events using a unified MermaidBlockEvent object. Listeners can call preventDefault() on the event to stop the component's default behavior:

  • copy — copy button clicked, signature: (ev: MermaidBlockEvent<{ type: 'copy'; text: string }>) (call ev.preventDefault() to stop the built-in clipboard write + "Copied" state)
  • export — export button clicked, signature: (ev: MermaidBlockEvent<{ type: 'export' }>)
  • openModal — request to open the pseudo-fullscreen modal, signature: (ev: MermaidBlockEvent<{ type: 'open-modal' }>)
  • toggleMode — toggle between source and preview, signature: (target: 'source' | 'preview', ev: MermaidBlockEvent<{ type: 'toggle-mode'; target: 'source' | 'preview' }>)

Intercept example

Completely override the component's default export behavior:

vue
<script setup lang="ts">
import type { MermaidBlockEvent } from 'markstream-vue'
import { MermaidBlockNode } from 'markstream-vue'

function onExport(ev: any /* MermaidBlockEvent */) {
  ev.preventDefault()
  // The component exposes the rendered SVG element on the event as `svgElement`.
  const svgEl = ev.svgElement as SVGElement | null
  if (!svgEl) {
    console.warn('No svg element available')
    return
  }
  const svgString = new XMLSerializer().serializeToString(svgEl)
  uploadSvg(svgString)
}
</script>

<template>
  <MermaidBlockNode :node="node" @export="onExport" />
</template>

Note: The event object includes both svgElement (DOM node) and svgString (serialized SVG) on export and openModal events — use whichever is more convenient.

Slot example — fully replace right-side controls

vue
<MermaidBlockNode :node="node" :showExportButton="false">
  <template #header-right>
    <button @click="downloadSvg">Download</button>
    <button @click="openCustomModal">Open custom modal</button>
  </template>
</MermaidBlockNode>
  • To implement custom export/upload behavior, call preventDefault() in the export listener and extract the SVG from the rendered DOM in your handler.
  • To fully replace the header UI, use the header-* slots and set the corresponding show* props to false to hide the default controls.
  • If Mermaid content originates from users/LLMs or any untrusted source, set :is-strict="true" so the component sanitizes the SVG and disables HTML labels; this closes the gap where crafted javascript: URLs or event handlers could sneak into the rendered output.
  • In AI chat scenarios, use onRenderError to show raw mermaid source instead of the default error message:
vue
<script setup lang="ts">
import { MermaidBlockNode } from 'markstream-vue'

function handleMermaidError(_err: unknown, code: string, container: HTMLElement) {
  // Show the raw mermaid text as a code block instead of an error message
  const pre = document.createElement('pre')
  pre.className = 'text-sm font-mono whitespace-pre-wrap p-4'
  pre.textContent = code
  container.replaceChildren(pre)
  return true // prevent default error display
}
</script>

<template>
  <MermaidBlockNode :node="node" :on-render-error="handleMermaidError" />
</template>

Notes:

  • svgString is already included in export and openModal event payloads (the serialized SVG string is available on the event), so consumers can upload or post the SVG without re-serializing.
  • This page is linked from the docs sidebar and a runnable playground demo is provided in the repo (route: /mermaid-export-demo, file: playground/src/pages/mermaid-export-demo.vue).

See also

Playground demo: there's a runnable playground page demonstrating how to intercept export and upload ev.svgString — see the playground route mermaid-export-demo (file: playground/src/pages/mermaid-export-demo.vue).

Try this — quick mermaid example you can paste into a component:

vue
<script setup lang="ts">
import MarkdownRender from 'markstream-vue'

const md = `\n\`\`\`mermaid\ngraph TD\nA-->B\n\`\`\`\n`
</script>

<template>
  <MarkdownRender :content="md" />
</template>