# react-super-mermaid
> Drop-in React Mermaid viewer. Renders any Mermaid diagram, then re-styles it after render with two signature themes — `colorful` (modern palette, soft shadows, slate edges, vibrant per-type colouring) and `sketch` (Excalidraw hand-drawn) — and layers on pan/zoom, in-diagram search, fullscreen, background toggle, and SVG/PNG/JPEG/WebP export. Mermaid, svg-pan-zoom and React are optional peer dependencies that are never bundled (inject an instance, dynamic-import the peer, or load from a CDN). TypeScript, SSR-safe, zero-config styling, ships a `'use client'` boundary for Next.js.
Key facts:
- Package: `react-super-mermaid` on npm. License MIT. Author markku636.
- Install: `npm i react-super-mermaid` then optionally `npm i mermaid svg-pan-zoom` (peers). For no-build pages, load mermaid from a CDN and install nothing.
- Entry component: ``. Give it a sized parent — it fills `height: 100%`.
- Themes: `colorful` (default), `sketch`, `auto`, and Mermaid's native `default` / `dark` / `neutral` / `forest`.
- Post-render styling is pure DOM manipulation in the browser; each pass early-outs on zero matches, so a Mermaid DOM change can never break rendering.
## Components and hooks
- `MermaidViewer` — full viewer with toolbar (theme picker, search, zoom, export, fullscreen, background). Props: `code` (required string), `theme`, `dark`, `toolbar`, `panZoom`, `touchGestures` (pinch-to-zoom + drag-to-pan on touch screens, default true, needs `panZoom`), `search`, `exportable`, `background` (show the background picker), `pattern` (`none|dots|grid`, default `dots`), `solidColor` (`string|null`; canvas surface color, `null` = transparent/follow page), `fullscreen`, `onFullscreenChange`, `keyboard`, `seed`, `fontUrl`, `mermaid` (`{instance?,cdnUrl?}`), `svgPanZoom`, `mermaidConfig`, `injectStyles`, `className`, `style`, `onRender`, `onError`. The background picker = preset surface swatches + a custom color well + an independent none/dots/grid pattern toggle (`BACKGROUND_PRESETS` / `PATTERN_OPTIONS` are exported).
- `MermaidDiagram` — diagram only (equivalent to ``).
- `useMermaidViewer` — hook backing the components for custom UIs.
- Imperative ref handle (`MermaidViewerHandle`): `zoomIn / zoomOut / fit / reset / actualSize / getZoomPercent / search / next / prev / clearSearch / exportSvg / exportPng / downloadSvg / downloadPng / getSvg / enterFullscreen / exitFullscreen / toggleFullscreen / isFullscreen / setPattern / cyclePattern / getPattern / setSolidColor / getSolidColor / getChecks / showChecks / focusCheck / openChecklist / closeChecklist`.
- `CheckCard` / `CheckPopover` / `CheckList` — the check-hint UI pieces, exported for custom layouts.
## Check hints (`%% @check`)
Attach "how do I diagnose this step?" notes to diagram nodes — severity badge on the node, a card with ordered steps, copyable SQL/KQL snippets, links, and a Kibana Discover URL.
- Authored **inside the mermaid source** so an LLM-generated diagram carries its own runbook in one fenced block; directives are stripped before mermaid parses the source. Props (`checks`) are the alternative/override channel — same `target` means the prop wins.
- Syntax: `%% @check [title]` opens a block; following `%% key: value` lines are its fields, ending at the next `%% @check` or a non-comment line. `key: |` starts a YAML-style block scalar for multi-line values (SQL). Reserved keys are `severity` (info/warn/error), `desc`, `steps`, `link` (`label | url`, repeatable), `match` (id/label), `elk` (KQL); **every other key becomes a copyable snippet whose language is the key name** (`sql:`, `kql:`, `sh:`…), so new snippet types need no parser change.
- `target` matches the author-written node id; quote it to match on label text instead. Multiple checks can share a target — the badge shows a count.
- Badges are SVG elements parented to their node, so they pan/zoom with the diagram and survive SVG **and** PNG export (styles are injected into the SVG, not only the page stylesheet).
- ELK links: declarative `elk={{ kibanaHost, dataViewId, timeFrom, timeTo }}` uses the built-in builder (no backend); `onResolveElkLink` overrides it for hosts that must resolve a data view server-side. Neither configured → the button degrades to "copy KQL" instead of a dead link.
- Toolbar gets a badge toggle + check-list drawer; `h` / `c` shortcuts. With zero checks the whole feature stays hidden.
## Hover tips (`%% @tip`)
A themed tooltip when the mouse rests on a node — the one-liner counterpart to check hints ("what does this step do?").
- Syntax: `%% @tip `; indented `%%` comment lines continue the same tip (joined with newlines). Quote the target (`%% @tip "Node label" …`) to match label text instead of the author id. Directives are stripped before mermaid parses the source, same as `%% @check`.
- Viewer props: `nodeTips` (default true, master switch), `tips` (`DiagramTip[]` or `Record` shorthand; same target overrides `%% @tip`), `tipsFromSource` (default true), `getNodeTip({ id, label, node })` (string = show, `null` = silence the node, `undefined` = fall through), `tipFallbackLabel` (default false; nodes without a tip show full label + id — useful when fitted diagrams squeeze long labels).
- A node carrying check hints (and no tip) shows the check summary on hover; the badge itself keeps its native tooltip. The tooltip follows the cursor, flips at canvas edges, hides during drag-pan, and is `pointer-events: none`.
## ORID diagrams (`orid`) — a diagram type Mermaid does not have
The ICA "focused conversation" method as a diagram: four fixed stages — Objective (facts) → Reflective (feelings) → Interpretive (meaning) → Decisional (action) — drawn as a vertical funnel, each stage a colour-coded band holding a row of items. Good for retrospectives, incident reviews and workshop notes, where a flowchart would force you to invent structure the method already gives you.
- Syntax: `orid`, then `title `, then a stage keyword line (`objective` / `reflective` / `interpretive` / `decisional`, optionally followed by a custom heading), then one indented line per item. Bullet prefixes (`- `, `* `, `• `) are optional and force item interpretation — use one when an item itself starts with a stage keyword. Stages render in canonical O→R→I→D order regardless of writing order; a declared-but-empty stage renders as a dashed "(待填)" placeholder. YAML frontmatter is preserved; an `orid` `title` becomes the chart title.
- Single-letter abbreviations are deliberately **not** accepted: an English item beginning `I feel…` would silently open an Interpretive stage and swallow everything after it.
- How it renders: `transpileOrid(code)` rewrites ORID into an equivalent `flowchart TB` (one subgraph per stage, `direction LR` + `~~~` invisible links to lay items out in rows, `classDef` for the semantic palette) *before* mermaid sees it. Everything downstream is unchanged — themes, pan/zoom, search, SVG/PNG export, `%% @check`, `%% @tip`. Item node ids are `O1`, `R2`, `I1`, `D3`… so check/tip directives can target them.
- `renderDiagram` / `MermaidViewer` / `MermaidEditor` transpile internally — nothing to wire up. Hosts that call `mermaid.render` themselves import the ~10 KB subpath entry: `import { transpileOrid } from 'react-super-mermaid/orid'` then `mermaid.render(id, transpileOrid(source))`. Non-ORID source passes straight through.
- Editing: like `timeline`, ORID has no coordinates to drag, so the editor hands it to a structured form (four stage cards, add/remove/reorder items, live preview) instead of the canvas.
- API (`react-super-mermaid/orid`, also re-exported from the main entry and `/editor`): `transpileOrid`, `isOridSource`, `oridToMermaid`, `parseOrid`, `serializeOrid`, `emptyOridModel`, `orderedStages`, `stageHeading`, `oridStageSpec`, `oridStageByKeyword`, `ORID_STAGES`, `ORID_PALETTE`, `oridItemClass`, `oridStageClass`.
## Framework-agnostic core API
- `renderDiagram({ code, container, theme, dark, seed, fontUrl, mermaidConfig, mermaid, injectStyles })` — one-shot render + post-process into a container, returns `{ svg, svgString, id }`.
- `loadMermaid({ source })` — resolve external mermaid: injected instance → peer `import('mermaid')` → CDN; memoized.
- `colorizeDiagram(svgOrRoot, { dark })` — apply the `colorful` post-process (palette + shadows + per-type colouring for flowchart / sequence / class / state / ER / pie / gantt / mindmap / timeline / journey / ORID). Invisible (`~~~`) links are left invisible.
- `boostLegibility(svgOrRoot)` — bump label font-weight for crisp text in every theme (weight-only, never changes colours). Applied automatically by the viewer.
- `sketchifyDiagram(svgOrRoot, { dark, seed })` — apply the Excalidraw hand-drawn post-process (sequence diagrams especially).
- `parseChecks(code)` / `stripCheckDirectives(code)` / `mergeChecks(base, overrides)` — the `%% @check` directive parser.
- `parseTips(code)` / `stripTipDirectives(code)` / `mergeTips(base, overrides)` / `normalizeTips(recordOrArray)` — the `%% @tip` directive parser.
- `attachHoverTips(svg, host, { renderId, tips, getTip, fallbackLabel, checksSummary, delay })` — bind hover tooltips to a rendered SVG for non-React hosts; `host` is the positioned container the tip div lives in; returns `{ destroy }`.
- `annotateChecks(svg, checks, { renderId, onActivate, visible })` — inject severity badges into a rendered SVG; returns a controller (`groups`, `unresolved`, `setVisible`, `focus`, `destroy`).
- `buildKibanaDiscoverUrl({ kibanaHost, dataViewId, kql, timeFrom, timeTo, columns })` — pure rison → Discover URL builder (no network). `elkLinkFromConfig(query, config)` applies a viewer's `elk` config to one check.
- `findDiagramNode(svg, target, { renderId, match })` / `authorIdFromDomId(domId, renderId)` / `nodeLabelText(el)` — map an author-written node id back to its rendered SVG element.
- `resolveTheme(theme, dark)`, `ensureStyles()`, `loadSvgPanZoom()`, and export helpers (`serializeLiveSvg`, `prepareSvgString`, `prepareSvgElement`, `rasterizeToBlob`, `svgBlob`, `downloadBlob`).
## Styling
- Styles auto-inject once (`injectStyles` default true) — no CSS import. Override via CSS variables on `.rsm-root`, e.g. `--rsm-accent`, `--rsm-border`, `--rsm-radius`, `--rsm-surface`.
- `sketch` uses Excalidraw's Virgil font fetched at runtime from the package's jsDelivr asset; falls back to `KaiTi / Comic Sans MS / cursive` if it can't load. `colorful` needs no font.
## Keyboard shortcuts
Focus the viewer: `/` or `Ctrl/Cmd+F` search · `+`/`-` zoom · `0` fit · `1` actual size · `w` fit width · `f` fullscreen · `b` cycle background pattern (none / dots / grid) · `h` toggle check badges · `c` toggle the check list · `Esc` closes the topmost layer (hint card → check list → search → fullscreen). Touch: pinch to zoom, two-finger drag to pan (inline a single finger scrolls the page; fullscreen a single finger pans).
## Links
- Source and full docs: https://github.com/markku636/react-super-mermaid
- npm: https://www.npmjs.com/package/react-super-mermaid
- Runnable demo: the `example/` directory (Vite + React).