Skip to content

Embedding

David Benson edited this page Oct 7, 2026 · 1 revision

This page covers the ways to put draw.io inside another application: the editor in embed mode, controlled with postMessage; the viewer library, which renders diagrams in your own page; and lightbox URLs. It is for developers integrating draw.io into a web app, CMS or tool. To show editable diagrams in GitHub READMEs and wikis, see Embed diagrams.

Choosing an approach

You want to Use Runs in
Let users create and edit diagrams that your app stores Embed mode An iframe or popup with embed.diagrams.net or your own instance
Show diagrams read-only, with zoom, layers, pages and links The viewer Your page (viewer-static.min.js)
Link to a diagram or show it in an iframe without code Lightbox URLs viewer.diagrams.net
Show a static picture that can still be edited later PNG or SVG with the diagram embedded (Embed diagrams, File format) Anywhere images work

Embed mode

In embed mode the editor has no storage of its own: your application passes the diagram in, and the editor hands it back when the user saves. The protocol is implemented in EditorUi.prototype.installMessageHandler (diagramly/EditorUi.js); the full reference of messages and options is embed-mode on drawio.com, and jgraph/drawio-integration has complete examples (a reusable diagram-editor.js wrapper, inline editing, local storage, WebDAV).

sequenceDiagram
    participant H as Host page
    participant E as Editor (iframe)
    H->>E: load https://embed.diagrams.net/?embed=1&proto=json
    E-->>H: {event: 'init'}
    H->>E: {action: 'load', xml: '...'}
    E-->>H: {event: 'load', ...}
    Note over E: user edits
    E-->>H: {event: 'autosave', xml} (if autosave: 1)
    E-->>H: {event: 'save', xml, exit}
    E-->>H: {event: 'exit', modified}
    H->>E: remove the iframe
Loading

Use embed.diagrams.net for embed mode; app.diagrams.net shows a warning banner when it is opened with embed=1. The editor waits for its plugins before it sends init (see Plugins).

A complete page

This page opens the editor in an iframe, loads a diagram, keeps the saved XML and closes the editor on Save & Exit or Exit:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>draw.io embed example</title>
  <style>
    iframe { position: fixed; inset: 0; width: 100%; height: 100%; border: 0; }
  </style>
</head>
<body>
  <button id="edit">Edit diagram</button>
  <pre id="saved"></pre>
  <script>
    var editorOrigin = 'https://embed.diagrams.net';
    var diagramXml = '<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/>' +
      '<mxCell id="2" value="Hello" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">' +
      '<mxGeometry x="40" y="40" width="120" height="60" as="geometry"/></mxCell>' +
      '</root></mxGraphModel>';
    var iframe = null;

    function receive(evt)
    {
      // Only accept messages from the editor frame created below
      if (iframe == null || evt.origin !== editorOrigin ||
        evt.source !== iframe.contentWindow || typeof evt.data !== 'string')
      {
        return;
      }

      var msg = JSON.parse(evt.data);

      if (msg.event == 'init')
      {
        iframe.contentWindow.postMessage(JSON.stringify({action: 'load',
          xml: diagramXml, autosave: 0, title: 'example.drawio'}), editorOrigin);
      }
      else if (msg.event == 'save')
      {
        diagramXml = msg.xml;
        document.getElementById('saved').textContent = diagramXml;

        if (msg.exit)
        {
          close();
        }
      }
      else if (msg.event == 'exit')
      {
        close();
      }
    }

    function close()
    {
      window.removeEventListener('message', receive);
      iframe.parentNode.removeChild(iframe);
      iframe = null;
    }

    document.getElementById('edit').addEventListener('click', function()
    {
      if (iframe == null)
      {
        window.addEventListener('message', receive);
        iframe = document.createElement('iframe');
        iframe.setAttribute('src', editorOrigin +
          '/?embed=1&proto=json&spin=1&saveAndExit=1&noSaveBtn=1');
        document.body.appendChild(iframe);
      }
    });
  </script>
</body>
</html>

saveAndExit=1&noSaveBtn=1 shows Save & Exit and Exit only, so every save closes the editor. The saved xml is a complete, uncompressed <mxfile> (as in a .drawio file, see File format) that you can pass to load again. The same flow works with window.open instead of an iframe; the editor then talks to window.opener.

URL parameters

Parameter Effect
embed=1 Turns on embed mode
proto=json JSON messages as described here (without it, the editor posts the plain string ready and receives raw XML)
spin=1 Shows a spinner until the diagram is loaded
configure=1 Sends {event: 'configure'} first and waits for {action: 'configure', config: {...}} before it starts; the config object is the editor configuration
saveAndExit, noSaveBtn, noExitBtn Choose the buttons (also settable in the load message)
modified, keepmodified Control the modified status text
p Loads plugins by registry id
ui, lang, dark Theme, language and dark mode, as in the normal editor

All URL parameters of the editor apply; see supported URL parameters.

Messages

Direction Message Purpose
Editor to host init Ready for load
Host to editor load xml (or xmlpng, or a descriptor), and options such as autosave: 1, title, modified, saveAndExit, noSaveBtn, noExitBtn, dark, rough
Editor to host load Sent after the diagram is loaded, with its bounds and scale
Editor to host save The user saved: xml, and exit: true for Save & Exit
Editor to host autosave After each change if the load message had autosave: 1
Editor to host exit The user closed the editor; modified tells whether there were unsaved changes
Host to editor export Requests format png, xmlpng, svg, xmlsvg, html, html2, xml or json; answered with an export event that has data (a data URI or text) and xml
Host to editor merge, patch, getDiff, template, dialog, prompt, status, spinner, layout, exit, ... Further actions, see the reference

The xml of a load message may be plain XML, compressed XML, a PNG data URI with an embedded diagram, an SVG data URI (data:image/svg+xml;base64, or ;utf8,) or a URI-encoded string; the editor extracts the diagram from each (extractDiagramXml in installMessageHandler). An empty string opens a blank diagram.

Your own instance

Embed mode works the same on a self-hosted instance (see Self-hosting): point the iframe at https://drawio.example.com/?embed=1&proto=json and use that origin in your origin check. Configure the instance as usual in PreConfig.js, or per embedding with configure=1. If your server sends X-Frame-Options or a frame-ancestors policy, it must allow the host page. Add your own plugins to the iframe URL with p after adding them to App.pluginRegistry in a fork, or load them for every page of the instance from PostConfig.js (see Plugins).

Inline editing

embedInline=1 is a variant for editing a diagram in place inside the host page: it implies embed=1, proto=json and the sketch theme, disables plugins, and sends the diagram back as an SVG export event when the user leaves the editor. See the inline example in jgraph/drawio-integration.

The viewer

The viewer renders diagrams in your own page, read-only, with optional toolbar, layers, tags, pages, links, collapse and expand, and a lightbox for the full-size view. It is GraphViewer.js plus the core graph code, built into two bundles (see Building):

File Contents
js/viewer-static.min.js The viewer and all JavaScript shapes; no code is evaluated at run time. The HTML export of the editor references this file.
js/viewer.min.js Smaller: JavaScript shape files are loaded on demand from SHAPES_PATH

Both are served from https://viewer.diagrams.net/js/ and are in src/main/webapp/js/ of this repository. Unless you set them before the script loads, the bundles fetch their resources from viewer.diagrams.net: STENCIL_PATH, SHAPES_PATH, STYLE_PATH, GRAPH_IMAGE_PATH, mxImageBasePath, mxBasePath, DRAW_MATH_URL and PROXY_URL default to https://viewer.diagrams.net/.... The committed bundles load stencil XML from STENCIL_PATH when a diagram uses a stencil, and this repository has no stencil XML; a bundle rebuilt from this repository includes stencils.min.js instead. To serve the viewer entirely from your own host, see Self-hosting.

Markup

<div class="mxgraph" style="max-width:100%;border:1px solid transparent;"
  data-mxgraph='{"highlight":"#0000ff","nav":true,"resize":true,"toolbar":"zoom layers lightbox","xml":"<mxGraphModel><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/><mxCell id=\"2\" value=\"Client\" style=\"rounded=1;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"20\" y=\"20\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell></root></mxGraphModel>"}'></div>
<script src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>

When the script runs, it calls GraphViewer.processElements(), which turns every element with the class mxgraph into a viewer, reading the JSON in data-mxgraph. Put the script after the elements. File > Embed > HTML in the editor generates this markup (with the attribute HTML-escaped, which is the safer form when the XML contains quotes or &).

From script

If window.onDrawioViewerLoad is defined when the bundle loads, the bundle calls it instead of processElements, so you decide when and what to render:

<div id="diagram"></div>
<script>
  window.onDrawioViewerLoad = function()
  {
    var xml = '<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/>' +
      '<mxCell id="2" value="Hello" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">' +
      '<mxGeometry x="20" y="20" width="120" height="60" as="geometry"/></mxCell></root></mxGraphModel>';
    var div = document.getElementById('diagram');
    div.setAttribute('data-mxgraph', JSON.stringify({xml: xml, toolbar: 'zoom', border: 10}));

    GraphViewer.createViewerForElement(div, function(viewer)
    {
      // viewer is a GraphViewer, viewer.graph the Graph
    });
  };
</script>
<script src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>

GraphViewer.processElements(classname) processes all elements with a class (default mxgraph), GraphViewer.createViewerForElement(element, callback) one element, and new GraphViewer(container, xmlNode, graphConfig) creates a viewer from a parsed XML node. Both examples on this page were run against the current viewer.

Options

The JSON in data-mxgraph (the graphConfig) accepts these keys, read in GraphViewer.prototype.init and related functions:

Key Meaning
xml The diagram: an <mxfile>, <mxGraphModel>, or the content of an SVG or HTML export
url Load the diagram from a URL instead (a plain XMLHttpRequest, so the server must allow CORS); takes precedence over xml
toolbar Space-separated buttons: pages, zoom, layers, tags, lightbox, plus your own keys defined in toolbar-buttons
toolbar-position, toolbar-nohide top (default), inline or bottom; true keeps the toolbar visible
zoom, border, center Initial scale (default 1), padding in pixels (default 8), centring
auto-fit, allow-zoom-in, allow-zoom-out, max-height, resize, responsive Sizing behaviour
page, pageId Initial page by index or id
layers, layerIds Visible layers by index (space-separated) or id
hiddenTags Tags to hide, per page
nav Collapse and expand of containers
highlight Colour of the hover highlight on cells with links
target self or blank for links
lightbox, edit, editable false disables the lightbox, open opens it in a new window; the Edit link in the lightbox (_blank opens a copy in the editor)
title Title in the toolbar
dark-mode dark, auto or light (default)
show-link-icons, show-tooltip-icons, show-note-icons Icons on cells with links, tooltips or notes
move Collapse and expand move the neighbouring cells

The descriptions for users are on drawio.com. GraphViewer.prototype.* defaults (for example GraphViewer.prototype.lightboxZIndex) can be changed before the viewers are created.

Lightbox and viewer URLs

viewer.diagrams.net is the editor in lightbox mode (the host name implies lightbox=1, see Init.js); on app.diagrams.net or your own instance, add lightbox=1. The diagram goes into the hash:

Hash Content
#U<url> The URI-encoded URL of a diagram file (.drawio, .xml, or a PNG or SVG with an embedded diagram). The editor fetches it directly from its own origin and known CORS-enabled hosts such as raw.githubusercontent.com, and through its proxy (PROXY_URL) otherwise.
#R<data> The URI-encoded diagram itself, plain or compressed with Graph.compress; this is what File > Publish > Link produces for local files
#G, #W, #H, ... Files in cloud storage, see supported location hash properties
https://viewer.diagrams.net/?highlight=0000ff&nav=1&title=schema.png#Uhttps%3A%2F%2Fraw.githubusercontent.com%2Fwiki%2Fjgraph%2Fdrawio%2Fimages%2Fschema.png

Other useful parameters are edit=_blank (an Edit button that opens a copy in the editor), layers=1, page-id, target and tags (supported URL parameters). The same URL in an <iframe> embeds the lightbox in a page; File > Embed > IFrame generates the markup.

Security notes

  • Check origins in both directions. The editor only accepts messages from the window that opened or contains it (evt.source is compared with window.opener or window.parent). Your page must check event.origin and event.source as in the example, and should post to the editor with its exact origin rather than *.
  • Treat what comes back as untrusted. The xml and exported data contain whatever the user (or the diagram they loaded) put in it. draw.io sanitises labels when it renders them, in the editor and in the viewer, but your application must not insert returned XML or SVG markup into its own DOM with innerHTML; show SVG exports through an <img> element or render the XML with the viewer. Never put secrets into a diagram you hand to the editor.
  • Sandboxing. The load and save flow above works in an iframe with sandbox="allow-scripts allow-same-origin" (tested); allow-same-origin is needed for the editor's local storage. Add allow-popups, allow-downloads or allow-modals only for the features that need them (opening links, downloads, printing).
  • The viewer runs in your page. Loading viewer-static.min.js from viewer.diagrams.net executes that script with your page's privileges; self-host the bundle if that is not acceptable. Diagram content is sanitised by the viewer, and links are checked with Graph.sanitizeLink, which rejects javascript: URLs.

More in Security.

See also

Clone this wiki locally