Use Mermaid text as an editable view of a live Grafloria diagram: export the current model, edit the visible Mermaid body, then load it back while retaining model data that Mermaid cannot express, including positions.
When to use this
Use the instance methods after mounting a canvas. DiagramInstance is the shared handle for the rendered model. exportText() returns Mermaid-compatible text, and loadText() parses that text and reconciles it into the same instance.
Use the framework bindings
Each binding exposes the same instance operations after its component mounts. Keep the instance in the binding’s initialization callback or hook; do not recreate it in a render function.
JavaScript
jsimport { render } from '@grafloria/element';
const stage = document.getElementById('stage');
const source = document.getElementById('source');
const instance = render({
nodes: [
{ id: 'start', label: 'Start', position: { x: 80, y: 60 }, size: { width: 140, height: 60 } },
{ id: 'work', label: 'Work', position: { x: 320, y: 60 }, size: { width: 140, height: 60 } },
{ id: 'done', label: 'Done', position: { x: 560, y: 60 }, size: { width: 140, height: 60 } },
],
edges: [
{ id: 'e1', source: 'start', target: 'work' },
{ id: 'e2', source: 'work', target: 'done' },
],
}, stage);
instance.renderNow();
source.value = instance.exportText();
document.getElementById('load').addEventListener('click', () => {
instance.loadText(source.value);
instance.renderNow();
});
html<div id="stage" style="height:400px"></div>
<textarea id="source" style="width:100%;height:220px"></textarea>
<button id="load">Load</button>
The canvas shows Start → Work → Done, and the textarea contains the exported text. Edit the textarea and choose Load to apply the text to the same mounted instance.
Angular
tsimport { AfterViewInit, Component, viewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DiagramCanvasComponent } from '@grafloria/angular';
@Component({
standalone: true,
imports: [DiagramCanvasComponent, FormsModule],
template: `
<div style="height:400px"><grafloria-diagram-canvas [nodes]="nodes" [edges]="edges" /></div>
<textarea [(ngModel)]="text" style="width:100%;height:220px"></textarea>
<button (click)="exportText()">Export</button><button (click)="loadText()">Load</button>
`,
})
export class MermaidTextComponent implements AfterViewInit {
canvas = viewChild.required(DiagramCanvasComponent);
text = '';
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' } },
];
edges = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }];
exportText(): void { this.text = this.canvas().exportText(); }
loadText(): void { this.canvas().loadText(this.text); }
ngAfterViewInit(): void { this.exportText(); }
}
The canvas renders Start → Work → Done. Export fills the textarea; edit it and choose Load to reconcile the edit into the mounted canvas.
Qwik
tsximport { component$, $, noSerialize, useSignal, type NoSerialize } from '@builder.io/qwik';
import { GrafloriaFlow, type DiagramInstance, type NodeSpec, type EdgeSpec } from '@grafloria/qwik';
const nodes: NodeSpec[] = [
{ 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: EdgeSpec[] = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }];
export default component$(() => {
const instance = useSignal<NoSerialize<DiagramInstance>>();
const text = useSignal('');
return <div style={{ height: '400px' }}><GrafloriaFlow defaultNodes={nodes} defaultEdges={edges}
onInit$={$((api: DiagramInstance) => { instance.value = noSerialize(api); text.value = api.exportText(); })} />
<button onClick$={() => { if (instance.value) text.value = instance.value.exportText(); }}>Export</button>
<button onClick$={() => { instance.value?.loadText(text.value); }}>Load</button>
<textarea value={text.value} onInput$={(_, element) => { text.value = element.value; }} />
</div>;
});
The mounted GrafloriaFlow shows the three nodes. Load applies edited text; Export reads the current model back into the textarea.
React
tsximport { useRef, useState } from 'react';
import { GrafloriaFlow, type DiagramInstance, type NodeSpec, type EdgeSpec } from '@grafloria/react';
const nodes: NodeSpec[] = [
{ 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: EdgeSpec[] = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }];
export default function MermaidTextDemo() {
const instance = useRef<DiagramInstance | null>(null);
const [text, setText] = useState('');
return <div style={{ height: 400 }}><GrafloriaFlow defaultNodes={nodes} defaultEdges={edges} style={{ height: '100%' }}
onInit={(api) => { instance.current = api; setText(api.exportText()); }} />
<button onClick={() => { if (instance.current) 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: 220 }} />
</div>;
}
The component renders Start → Work → Done and keeps the live instance in a ref. Editing the controlled textarea and selecting Load changes the mounted diagram.
Vue
vue<script setup lang="ts"> import { ref } from 'vue'; import { GrafloriaFlow, type DiagramInstance, type NodeSpec, type EdgeSpec } from '@grafloria/vue'; const text = ref(''); let instance: DiagramInstance | null = null; const nodes: NodeSpec[] = [ { 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: EdgeSpec[] = [{ id: 'e1', source: 'start', target: 'work' }, { id: 'e2', source: 'work', target: 'done' }]; function onInit(api: DiagramInstance) { instance = api; text.value = api.exportText(); } function exportText() { if (instance) text.value = instance.exportText(); } function loadText() { instance?.loadText(text.value); } </script> <template><div style="height:400px"><GrafloriaFlow :default-nodes="nodes" :default-edges="edges" @init="onInit" style="height:100%" /> <button @click="exportText">Export</button><button @click="loadText">Load</button><textarea v-model="text" style="width:100%;height:220px" /></div></template>
The mounted component shows Start → Work → Done. v-model supplies edited Mermaid text to loadText(); exportText() reads it back from the same instance.
Inspect text before mounting
Use importDiagramText when you need to parse text before deciding how to mount it. It returns an ImportTextResult. The live canvas path remains loadText() because it reconciles the result into a rendered instance.
See it running
Open the Mermaid text demo to edit Mermaid text and apply it to the canvas. Its source follows the same flow.
Was this page helpful?