prosemirror-mermaid
v0.0.0
Published
ProseMirror plugin for rendering Mermaid diagrams in code blocks. Extensible and wrappable as a Tiptap extension.
Downloads
809
Maintainers
Readme
Prosemirror Mermaid
🧩 A lightweight ProseMirror plugin that renders Mermaid diagrams directly inside the editor — with live updates, caching, and tight SVG cropping.
✨ Features
- Live rendering — Mermaid diagrams update automatically as you type.
- Debounced updates — Smooth, performant re-rendering (default: 300 ms).
- Smart caching — Re-renders only when the diagram source changes.
- Syntax highlighting — Works seamlessly with
lowlightandlowlight-mermaid. - Tight SVG cropping — Uses
@svg-fns/layoutfor clean, whitespace-free output. - Robust architecture — Follows ProseMirror best practices via widget decorations and plugin-managed lifecycle.
🚀 Installation
pnpm add prosemirror-mermaidor
npm install prosemirror-mermaidor
yarn add prosemirror-mermaid🧩 Usage
import { EditorState } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { mermaidPlugin } from "prosemirror-mermaid";
import mermaid from "mermaid";
// Important: initialize Mermaid yourself
mermaid.initialize({ startOnLoad: false });
const state = EditorState.create({
schema,
plugins: [
// ... other plugins
mermaidPlugin({ name: "codeBlock" }),
],
});
const view = new EditorView(document.querySelector("#editor"), { state });⚙️ Options
| Option | Type | Default | Description |
| ------------------- | ----------------------------------- | ------------- | ---------------------------------------------------------------------------------------------- |
| name | string | 'codeBlock' | Node type treated as Mermaid block. |
| lowlight | ReturnType<typeof createLowlight> | — | Enables syntax highlighting. Registers mermaid, mmd, and mindmap grammars automatically. |
| debounce | number | 300 | Delay (ms) before re-rendering after edits. |
| mermaidConfig | MermaidConfig | — | Pass directly to mermaid.initialize(). |
| classList | string[] \| string | — | CSS classes applied to each diagram container. |
🧠 Node Requirements
Your ProseMirror schema’s Mermaid node (usually codeBlock) must include:
language: must be"mermaid","mmd", or"mindmap".id: unique identifier (e.g.,m1234abcd).
This is typically managed by your editor or nodeView logic.
If you’re using tiptap, you can generate stable IDs via an addAttributes() extension override.
🧩 Example Integration (Tiptap)
import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
import { createLowlight } from "lowlight";
import { mermaidPlugin } from "prosemirror-mermaid";
import mermaid from "mermaid";
const lowlight = createLowlight();
mermaid.initialize({ startOnLoad: false });
const editor = useEditor({
extensions: [
CodeBlockLowlight.configure({ lowlight }).extend({
addAttributes() {
const parentAttrs = this.parent?.() ?? {};
return {
...parentAttrs,
id: {
default: () => `m${crypto.randomUUID().slice(0, 8)}`,
parseHTML: element =>
element.getAttribute("data-id") || `m${crypto.randomUUID().slice(0, 8)}`,
renderHTML: attributes => {
if (!attributes.id) return {};
return { "data-id": attributes.id };
},
},
};
},
addProseMirrorPlugins() {
return [
...(this.parent?.() || []),
mermaidPlugin({
name: this.name,
lowlight: this.options.lowlight,
classList: "mermaid",
}),
];
},
}),
],
});🧰 Internals
- Uses
Decoration.widgetto inject rendered SVGs after code blocks. - Maintains per-node render cache, debounce timers, and code cache.
- Relies on
@svg-fns/iofor safe SVG parsing andtightlyCropSvgfor layout cleanup. - Handles render errors gracefully with inline messages.
🪄 Example Styling
.mermaid-container {
display: flex;
justify-content: center;
padding: 0.5rem;
overflow-x: auto;
background: var(--code-bg, #fafafa);
border-radius: 0.5rem;
}🙏 Credits
- Mermaid for the visualization engine
- ProseMirror for the editing framework
- @svg-fns for SVG utilities
- lowlight-mermaid for syntax support
License
This library is licensed under the MPL-2.0 open-source license.
Please enroll in our courses or sponsor our work.
