Grafloria keeps Mermaid-compatible text readable while a lossless sidecar carries the canvas document: semantic node types describe what each entity means, and the sidecar preserves geometry that Mermaid does not express.
How the parts fit together
mermaidflowchart LR text["Mermaid-compatible body"] --> parse["Text parser"] sidecar["%%grafloria:document sidecar"] --> model["Live diagram model"] parse --> model model --> canvas["Rendered canvas"] model --> export["Text + sidecar"]
The Mermaid body carries structure, labels, and diagram direction. Importing it creates typed entities such as flowchart:process and flowchart:decision; the renderer can therefore choose the corresponding glyphs and layout behavior. The text parser exposes this result through importDiagramText, whose diagram is a live DiagramModel.
Grafloria's sidecar is a %%grafloria:document comment. Mermaid-compatible renderers ignore it, while Grafloria reads the serialized document from it. Positions, sizes, styles, ports, groups, and viewport data therefore survive an export/import round trip even though they are not part of ordinary Mermaid syntax.
Put Mermaid text into a live canvas
Use render to mount a real canvas, then use the returned DiagramInstance to load text into that mounted diagram. loadText() reconciles the parsed result into the existing instance; it does not discard the renderer, listeners, plugins, or selection.
tsimport { render } from '@grafloria/element';
const host = document.createElement('div');
host.id = 'canvas';
host.style.width = '800px';
host.style.height = '400px';
document.body.append(host);
const instance = render(
{
nodes: [
{
id: 'start',
label: 'Loading',
position: { x: 60, y: 80 },
size: { width: 150, height: 60 },
},
],
edges: [],
},
host,
);
const mermaid = `flowchart
start[Start] --> gate{Gate}
gate --> ship[Ship]`;
const loaded = instance.loadText(mermaid);
if (loaded.unsupported) {
throw new Error(`Unsupported diagram type: ${loaded.unsupported}`);
}
const firstNode = loaded.diagram.getNodes()[0];
if (!firstNode) {
throw new Error('The text contains no nodes');
}
instance.renderNow();
const exported = instance.exportText();
const status = document.getElementById('status');
if (status) {
status.textContent = `${firstNode.type}; sidecar: ${exported.includes('%%grafloria:document')}`;
}
With a host such as <div id="canvas" style="height: 400px"></div>, the canvas shows Start, Gate, and Ship connected from left to right. The status reports flowchart:process for the first node and sidecar: true. The initial Loading node is reconciled away because the Mermaid text defines the current node set.
Export and re-import
Call instance.exportText() after a user arranges the canvas. Its visible body remains Mermaid-compatible; by default, the output also contains the document sidecar and a body hash. Feeding that string to loadText() restores the document in the same live instance, including the canvas positions and other data that the body cannot represent.
When the body hash still matches, the default import preference uses the sidecar. If a person edits the Mermaid body, the returned result sets bodyEdited to true; the edited structure and labels take effect, while the sidecar remains the base for information the text cannot express. Check sidecarInvalid when a sidecar comment exists but its JSON is malformed. For a diagram type Grafloria recognises but does not support, unsupported identifies the type instead of silently treating it as another diagram.
The lower-level importDiagramText function is useful when parsing must happen before a canvas exists—for example, to inspect source, bodyEdited, or unsupported. Use the instance methods when the result belongs in a mounted canvas.
What the text does not own
The Mermaid body is the human-readable semantic layer: entities, relationships, labels, shapes, and direction. The sidecar is the fidelity layer: exact model state needed to reproduce the canvas. A pure Mermaid file without a sidecar remains importable, but its layout and other non-Mermaid details follow the lossy text boundary rather than a previous canvas arrangement.
For a saved document whose full model is the source of truth, use the JSON document path and fromDocument rather than projecting the model back into plain node and edge specs. For a text file meant to remain readable in Git and renderable by Mermaid, use the text path described here.
Was this page helpful?