Skip to content
D
Documentation

Import diagram text and files

how-to
6 min readUpdated

Use diagram text when you want a file you can review in git and a canvas you can edit by dragging. Load Mermaid into a mounted instance, export the edited document with its sidecar, or import an existing draw.io file. The examples below show Plan → Build → Ship beside an editable text pane.

The text body is Mermaid-compatible. The %%grafloria:document comment carries the document data that Mermaid cannot express, and %%grafloria:body-hash detects edits to the body. Mermaid consumers ignore these comments; Grafloria reads them back.

1. Install the binding you use

Run the matching command in your browser application's project.

For JavaScript:

bash
npm install @grafloria/element @grafloria/engine @grafloria/renderer

For Angular:

bash
npm install @grafloria/angular @angular/common @angular/core @angular/forms @angular/platform-browser @grafloria/engine @grafloria/renderer @grafloria/element rxjs

For Qwik:

bash
npm install @grafloria/qwik @builder.io/qwik @grafloria/engine @grafloria/renderer @grafloria/element

For React:

bash
npm install @grafloria/react react react-dom @grafloria/engine @grafloria/renderer @grafloria/element

For Vue:

bash
npm install @grafloria/vue vue @grafloria/engine @grafloria/renderer @grafloria/element

2. Share the data and import helpers

Use NodeSpec and EdgeSpec for the initial data. Keep the mounted DiagramInstance as the editing surface: exportText() returns a string, and loadText() reconciles text into its live model.

importDrawio accepts plain <mxGraphModel> XML and compressed or uncompressed <mxfile> documents. exportDiagramText converts its imported model to sidecar-carrying text. Loading that text uses the same instance API as the Mermaid editor, without projecting away ports, groups or styles.

Save this file alongside your component or entry point. The helpers return status text for your UI; they do not print a service response or replace the mounted canvas.

ts
import type { DiagramInstance, NodeSpec, EdgeSpec } from '@grafloria/renderer';
import { importDrawio, exportDiagramText } from '@grafloria/engine';

export const nodes: NodeSpec[] = [
  { id: 'plan', label: 'Plan', position: { x: 40, y: 80 }, size: { width: 140, height: 60 } },
  { id: 'build', label: 'Build', position: { x: 260, y: 80 }, size: { width: 140, height: 60 } },
  { id: 'ship', label: 'Ship', position: { x: 480, y: 80 }, size: { width: 140, height: 60 } },
];
export const edges: EdgeSpec[] = [
  { id: 'e1', source: 'plan', target: 'build' },
  { id: 'e2', source: 'build', target: 'ship' },
];

export function applyText(api: DiagramInstance, text: string): string {
  try {
    const result = api.loadText(text);
    api.renderNow();
    api.fitView(40);
    return result.source === 'sidecar'
      ? 'Loaded the document sidecar'
      : result.sidecarMerged
        ? 'Applied the body edit onto the sidecar document'
        : 'Parsed Mermaid text';
  } catch (error) {
    return error instanceof Error ? error.message : 'Text import failed';
  }
}

export async function applyDrawio(api: DiagramInstance, text: string): Promise<string> {
  const result = await importDrawio(text);
  if (!result.diagram) return result.error ?? 'No readable first page';
  const status = applyText(api, exportDiagramText(result.diagram));
  return [status, ...result.warnings].join('\n');
}

3. Mount the editor

Choose one binding. Each editor exports its initial canvas into the textarea. Edit build[Build] to build[Verify], keeping the sidecar comments, then press Load Mermaid: the middle box reads Verify and the surviving nodes retain their sidecar geometry. Press Export after dragging a node to capture its new arrangement. Paste XML, or choose a .drawio file, then press Import draw.io to replace the canvas content with the first imported page.

These editors add a text snapshot and explicit export and import actions to the JavaScript render, React GrafloriaFlow, Vue GrafloriaFlow and Qwik GrafloriaFlow mounts; see group and nest nodes for mounting and instance storage.

Angular exposes DiagramCanvasComponent. Its text loader differs from the renderer instance's loader:

Known issue: Angular's loadText(text) applies parser output without rejecting unsupported or erroneous bodies, and does not adopt diagram-level grammar metadata or replace existing groups. Until it is fixed, validate with importDiagramText() and replace the canvas's active diagram with the parsed model.

The intended Angular call is this.canvas().loadText(this.text). The Angular tab implements the workaround with importDiagramText and DiagramEngine, so an invalid import leaves the current diagram intact and a non-flowchart retains its export grammar. It explicitly schedules a repaint after loading.

ts
import { render } from '@grafloria/element';
import { nodes, edges, applyText, applyDrawio } from './diagram-text';

const root = document.createElement('section');
document.body.append(root);
const host = document.createElement('div');
host.style.height = '400px';
const source = document.createElement('textarea');
source.rows = 10;
source.style.width = '100%';
const status = document.createElement('pre');
const file = document.createElement('input');
file.type = 'file';
file.accept = '.drawio,.xml';
const exportButton = document.createElement('button');
exportButton.textContent = 'Export';
const loadButton = document.createElement('button');
loadButton.textContent = 'Load Mermaid';
const drawioButton = document.createElement('button');
drawioButton.textContent = 'Import draw.io';
root.append(host, source, exportButton, loadButton, file, drawioButton, status);
const api = render({ nodes, edges }, host);
api.renderNow();
api.fitView(40);
source.value = api.exportText();
exportButton.onclick = () => { source.value = api.exportText(); };
loadButton.onclick = () => { status.textContent = applyText(api, source.value); };
file.onchange = async () => {
  const selected = file.files?.[0];
  if (selected) source.value = await selected.text();
};
drawioButton.onclick = async () => {
  status.textContent = await applyDrawio(api, source.value);
};

// Call this when your application removes this editor.
export function unmountEditor(): void {
  api.dispose();
  root.remove();
}

The text pane is an explicit snapshot, not an automatic mirror of every canvas gesture. Press Export to refresh it. The framework components own their canvas teardown; the JavaScript sample exposes an unmount function for its host application.

The JavaScript editor shows Plan → Build → Ship above the exported Mermaid text, with Export, Load Mermaid, file selection and Import draw.io controls.

The Angular editor starts with the same nodes and exported text.

The Angular editor shows Plan → Build → Ship above its text pane and import controls.

The Qwik editor holds the text as serializable state beside its live instance.

The Qwik editor shows the three connected boxes, exported Mermaid text and import controls.

The React editor exposes the same explicit export and load workflow.

The React editor shows Plan → Build → Ship, its text pane and the Export, Load Mermaid and Import draw.io controls.

The Vue editor also starts with the exported body and document sidecar in its textarea.

The Vue editor shows the three connected boxes above the Mermaid text and file import controls.

Try the live Mermaid round-trip editor or the draw.io importer.

4. Compose architecture text

Paste this source into any editor above and press Load Mermaid. Cloud becomes a region containing Web app and API. The sided line exits Web app on the right and enters API on the left; Grafloria uses those sides to arrange the services. No custom layout plug-in is needed.

mermaid
architecture-beta
  group cloud(cloud)[Cloud]
  service web(server)[Web app] in cloud
  service api(server)[API] in cloud
  web:R -[HTTPS]-> L:api

For a row-and-column composition, paste this instead. columns 3 defines the grid, :3 spans a row, and space leaves a hole.

mermaid
block-beta
  columns 3
  title["Application"]:3
  web["Web app"] space api["API"]
  db[("Database")]:3
  web --> api
  api --> db

Press Export to obtain text in the diagram's grammar, then Load Mermaid to read that exported text back. See the live architecture and block demo for nested regions and layered grids.

Supported text and import results

The text format reads and writes these families:

HeaderUse it for
flowchart, graphNodes, labeled edges and subgraphs
erDiagramEntities and relationships
classDiagramClasses and relationships
stateDiagram, stateDiagram-v2States and transitions
architecture-betaServices, regions and sided lines
block-betaGrids, spans, spaces and nested blocks

The parser returns an ImportTextResult. Inspect source to distinguish a sidecar load from a body parse, bodyEdited for a hash mismatch, and sidecarMerged for an edit applied onto the sidecar base. sidecarInvalid identifies a sidecar whose JSON cannot be parsed. unsupported names a recognized but unsupported type, such as sequenceDiagram; errors lists parser diagnostics with line information.

Standalone importDiagramText() is best effort: readable lines can produce a partial model. The renderer instance's loadText() rejects empty text, unsupported types and body parse errors before changing the canvas. The sample catches that error and displays its message. Angular needs the validation workaround above.

For draw.io, show warnings even when a diagram imports successfully: each warning names a dropped or approximated construct. Unreadable input returns error, not a thrown exception. Multi-page files expose pages; each page has its own name, diagram, warnings and optional error. The samples display the first page. For a page picker, select a readable entry from pages and load exportDiagramText(page.diagram) through the same helper; a corrupt later page does not invalidate the other pages.

Options and round-trip boundaries

Pass these options to the instance's text methods, or to the corresponding engine text functions:

OptionTypeDefaultWhat it does
exportText({ lossless })booleantrueIncludes the document sidecar and body hash; false returns only the Mermaid body.
exportText({ positions })booleanfalseWrites readable %%grafloria:at comments for exact node and zone positions and sizes.
loadText(text, { prefer })'auto' | 'sidecar' | 'text''auto'Uses the sidecar unless the body hash detects an edit; 'sidecar' ignores body edits; 'text' ignores the sidecar.

Keep both sidecar comments for a document round trip. In automatic mode, a body edit changes structure, labels and shapes on the sidecar base; surviving nodes retain their geometry, styles and ports. Forcing 'text', or exporting with lossless: false, crosses the best-effort boundary: pure Mermaid does not carry all data bags, port geometry, group nesting or viewport data.

“Lossless” refers to document content, not the viewing session. Text export strips node/link selection, hover and focus state and derived routed link points; manual waypoints remain. The renderer instance's loadText() reconciles content and grammar metadata, but does not restore the sidecar's camera into the mounted viewport. The JavaScript, React, Vue and Qwik editors deliberately frame the imported content with fitView(40) instead.

Known issue: The renderer instance's loadText() does not transfer saved comment threads or non-grammar diagram-level metadata into the mounted model, even though the sidecar and the imported model contain them. Until it is fixed, use the shared saved-document workflow rather than this text loader for documents that need those fields preserved.

The intended round trip is api.loadText(api.exportText()). In the current renderer, that call transfers nodes, links, groups, strokes and only the listed grammar metadata keys; it does not replace arbitrary diagram metadata or restore saved comments. These text editors therefore do not provide a complete document round trip for comment-bearing or application-metadata-bearing diagrams. Use save and restore documents for those diagrams.

draw.io is an import-only format here. Export the migrated canvas as Grafloria text or a shared saved document, not as a .drawio file. For document loading into a new mount, use fromDocument, which restores models and supplies the mounted wiring for groups and kits. Avoid hand-projecting an imported model to a short node/edge tuple; see save and restore documents.

Was this page helpful?