Use Mermaid as a human-editable view of a live Grafloria canvas: load Mermaid text into the instance, change its labels or links, then export Mermaid-compatible text with the document's positions and styling preserved.
When to use this
Use the instance's exportText() and loadText() when the diagram is already mounted. Exported
text contains a Mermaid body followed by Grafloria sidecar comments. Mermaid consumers render the
body and ignore the comments; Grafloria uses the sidecar to retain information Mermaid does not
represent, including positions and styling.
For a one-off JavaScript mount, start with render, which
returns a DiagramInstance.
For framework applications, keep the instance supplied by the binding's component ready callback.
Import, edit, and export
- Give the canvas host a resolved height. A host with no height produces a blank canvas.
- Mount a diagram with nodes and edges.
- Export after initialization and after the canvas has painted, or from a user action.
- Let the user edit the Mermaid body, then call
loadText(text)on the same instance. - Call
exportText()again to save the edited diagram.
The first load of untouched exported text uses the sidecar and restores the exact document. If the
body changed, loadText() detects the edit and applies the Mermaid text on top of the sidecar
model. Existing nodes and links are reconciled into the live model rather than replacing the
model, so unchanged positions remain available.
JavaScript
jsimport { render } from '@grafloria/element';
const host = document.createElement('div');
host.style.height = '400px';
host.style.width = '800px';
const editor = document.createElement('textarea');
editor.style.width = '100%';
editor.style.height = '180px';
const apply = document.createElement('button');
apply.textContent = 'Apply Mermaid edit';
document.body.append(host, editor, apply);
const instance = render({
nodes: [
{ id: 'plan', label: 'Plan', position: { x: 60, y: 90 }, size: { width: 150, height: 66 } },
{ id: 'build', label: 'Build', position: { x: 300, y: 90 }, size: { width: 150, height: 66 } },
{ id: 'ship', label: 'Ship', position: { x: 540, y: 90 }, size: { width: 150, height: 66 } },
],
edges: [
{ id: 'e1', source: 'plan', target: 'build' },
{ id: 'e2', source: 'build', target: 'ship' },
],
}, host);
instance.renderNow();
editor.value = instance.exportText();
apply.addEventListener('click', () => {
editor.value = editor.value.replace('Plan', 'Design');
instance.loadText(editor.value);
editor.value = instance.exportText();
});
window.addEventListener('pagehide', () => instance.dispose(), { once: true });
The code mounts the flow, changes Plan to Design in the Mermaid body, and loads that edit back
into the same instance. The canvas shows the new label while the sidecar keeps the existing node
positions.
React
GrafloriaFlow owns the rendered canvas; capture its
onInit instance rather than constructing a second renderer.
textimport { useRef, useState } from 'react'; import { GrafloriaFlow } from '@grafloria/react'; import type { DiagramInstance } from '@grafloria/react'; const nodes = [ { id: 'start', position: { x: 80, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Start' } }, { id: 'work', position: { x: 320, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Work' } }, { id: 'done', position: { x: 560, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Done' } }, ]; const edges = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }]; export default function MermaidEditor() { const instance = useRef<DiagramInstance | null>(null); const [text, setText] = useState(''); return <div style={{ display: 'flex', height: '400px' }}> <GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} style={{ flex: 1 }} onInit={(api) => { instance.current = api; setText(api.exportText()); }} /> <div style={{ width: 340 }}> <button onClick={() => setText(instance.current?.exportText() ?? '')}>Export</button> <button onClick={() => instance.current?.loadText(text)}>Load</button> <textarea value={text} onChange={(event) => setText(event.target.value)} style={{ width: '100%', height: '350px' }} /> </div> </div>; }
The left side renders the three nodes; editing the textarea and choosing Load reconciles that text into the same instance.
Vue
text<script setup lang="ts"> import { ref } from 'vue'; import { GrafloriaFlow } from '@grafloria/vue'; import type { DiagramInstance } from '@grafloria/vue'; const text = ref(''); let instance: DiagramInstance | null = null; const nodes = [ { id: 'start', position: { x: 80, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Start' } }, { id: 'work', position: { x: 320, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Work' } }, { id: 'done', position: { x: 560, y: 60 }, size: { width: 140, height: 60 }, data: { label: 'Done' } }, ]; const edges = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }]; function onInit(api: DiagramInstance) { instance = api; text.value = api.exportText(); } </script> <template> <div style="display:flex;height:400px"> <GrafloriaFlow :default-nodes="nodes" :default-edges="edges" @init="onInit" /> <div style="width:340px"> <button @click="text = instance?.exportText() ?? ''">Export</button> <button @click="instance?.loadText(text)">Load</button> <textarea v-model="text" style="width:100%;height:350px" /> </div> </div> </template>
The canvas and editor stay side by side. Load applies the current textarea value; Export replaces it with the current Mermaid-compatible representation.
Qwik
For the complete Qwik setup and shared text workflow, see Text and lossless round trips; this page focuses on applying the edited text to the mounted canvas.
React
tsx// import { GrafloriaFlow } from '@grafloria/react';
// Render <GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} onInit={setInstance} />.
// Set text from instance.exportText(); call instance.loadText(text) from Load.
Vue
tsx// import { GrafloriaFlow } from '@grafloria/vue';
// Render <GrafloriaFlow :default-nodes="nodes" :default-edges="edges" @init="onInit" />.
// Set text from instance.exportText(); call instance.loadText(text) from Load.
Angular
ts// import { DiagramCanvasComponent } from '@grafloria/angular';
// Mount <grafloria-diagram-canvas [(nodes)]="nodes" [(edges)]="edges" />.
// Call canvas.exportText() for Export and canvas.loadText(text) for Load.
What the text contains
exportText() returns a Mermaid-shaped flowchart body and, by default, a
%%grafloria:document sidecar. The sidecar carries the exact document, while a body hash lets
loadText() distinguish untouched exported text from a hand edit. An untouched round trip returns
the sidecar source; a changed body returns the text source.
For parser-only workflows, importDiagramText
returns an import result without mounting a canvas. For model-only export,
exportDiagramText writes the same
Mermaid-compatible representation. Use those lower-level functions when no live canvas exists;
use the instance methods when the user is editing a rendered diagram.
Unsupported Mermaid diagram types report an unsupported result. Do not render that result as a
different diagram type; inspect it and leave the current canvas intact.
Live demos
-
Mermaid text shows sidecar export, body editing, and position preservation.
-
Mermaid viewer lets you paste or select Mermaid text and reports unsupported diagram types rather than displaying a blank canvas.
-
Mermaid architecture and block diagrams demonstrates editable architecture-beta and block-beta text, including groups, spans, and styles.
Was this page helpful?