Skip to content

Draw.io

Put a .drawio.svg that carries an editable copy on the page as an ordinary image; hovering gives the reader a button that opens the Draw.io editor.

The Draw.io integration has neither a fence nor a shortcode — it uses plain Markdown images. Tick “Include a copy of my diagram” when exporting from Draw.io and the SVG or PNG carries an mxfile copy inside it; the theme’s runtime spots that copy and adds an edit button to the image. It suits diagrams readers are meant to take away and change. A diagram that is only there to be looked at is an ordinary image.

Shortest form

The syntax is the plain image syntax. The filename does not matter; .drawio.svg is only a convention.

Source
![The Hugo build pipeline: content goes through Hugo and out as public](pipeline.drawio.svg)
{width="620" height="140"}
The Hugo build pipeline: content goes through Hugo and out as public

An export that carries an mxfile copy is wrapped in a .drawio container. Hover it and a pencil button appears at the bottom right; clicking lays a full-screen iframe over the page and loads the editor the site configured.

How the copy is detected

The runtime looks at one thing: whether the file’s contents contain mxfile. The filename is irrelevant. A hand-drawn SVG written exactly the same way — a block image with the same attribute line — carries no copy, so it gets no button.

Source
![The three columns of the documentation shell: sidebar, article, table of contents](plain-shell.svg)
{width="620" height="140"}
The three columns of the documentation shell: sidebar, article, table of contents

With a caption

Draw.io images go through the ordinary image render hook, so every image attribute still applies. Add caption for a captioned figure; the edit button still appears on the image.

Source
![The Hugo build pipeline](pipeline.drawio.svg)
{caption="Content, configuration and theme templates flow into Hugo and out as public/" width="620" height="140"}
The Hugo build pipeline
Content, configuration and theme templates flow into Hugo and out as public/

As a numbered figure

Add {#id num=…} for a cross-referenceable numbered figure, which xref can reach and which appears in the list of figures like any other.

Source
![The Hugo build pipeline](pipeline.drawio.svg)
{#fig_pipeline num="1-1" caption="From content to a static site" width="620" height="140"}
The Hugo build pipeline
Figure 1-1 From content to a static site

The complete numbering and cross-reference rules are in publishing books.

SVG or PNG

Both are recognized. A Draw.io PNG export can carry the same copy in a text chunk, and the runtime’s test is identical.

Source
![The Hugo build pipeline (PNG export)](pipeline.drawio.png)
{width="620" height="140"}
The Hugo build pipeline (PNG export)

Prefer SVG in documentation: it scales without loss, its text is real text (searchable, readable by screen readers) and its diffs are legible. Use PNG when the diagram is very complex or the target platform cannot take SVG. Only PNG can go through Hugo’s image processing; operations on SVG warn and leave the source unchanged, and strict builds reject the warning.

What the button does

Three things, in order.

Lay an overlay over the page

A full-screen div.drawioframe is inserted holding an iframe whose address is the configured drawio_server plus a fixed query string (embed=1&ui=atlas&proto=json&saveAndEdit=1&noSaveBtn=1).

Hand the diagram to the editor

Once the editor is ready, the runtime sends this image’s contents — the mxfile copy included — into the iframe as a data URL. That step does not go through your server.

Save and write back

Saving in the editor makes it export in the original format, SVG or PNG, and the browser downloads it under the same name. The runtime never writes to the repository: overwrite the file in content/ with what you downloaded and commit it yourself.

The edit button is there so a reader can take the diagram away and change it. It is not online editing of the site.

The editor address

hugo.yml
params:
  drawio:
    enable: true
    drawio_server: https://drawio.internal.example/
  • enable: true without drawio_server warns and disables editing; strict builds fail on that warning. The theme does not pick a public service.
  • When editing has to stay inside the organization, deploy a self-hosted editor and point at it.
  • The public endpoint https://embed.diagrams.net/ works, and the reader’s diagram then travels to a third-party page.

Both keys are defined in Configuration.

Output

Output Shape
HTML A plain <img> or <figure>; once enabled, the runtime wraps an image that carries a copy in <div class="drawio"> and adds the button
Print The image prints as usual; the button is hidden except on hover, so it never reaches paper
Markdown Plain Markdown image syntax
RSS A plain <img> with an absolute URL and no button

The image itself exists in all four states; the edit button is an increment on top.

Parameter reference

There are no fence or shortcode parameters of its own. The image attribute line is the one from Images: caption, width, height, link, #id, num, command, options.

Site parameters (hugo.yml):

params.drawio.enable , bool , defaultfalse
With it off no script loads and an image is just an image
params.drawio.drawio_server , string , defaultnone
The editor address; required when enable: true

Limits

  • The runtime loads only when rendered page content contains .svg or .png candidates. It groups matching images by URL, then reads each URL once to look for mxfile.
  • Forget to tick “Include a copy of my diagram” on export and the image is just an image, with no button.
  • Editing needs the editor and never writes back: offline, the images display fine and the button does nothing; saving is a browser download, and replacing the file and committing it are manual.
  • The button appears on hover only: touch devices have no hover, so readers may not find it. Do not present editability as a headline feature.
  • Colours do not follow the colour scheme: an exported SVG has fixed colours. Set fills to none and use neutral greys for lines and text and it reads in both modes.
  • Images — captions, numbering, sizing and zoom in full
  • PlantUML — the other integration that needs a server
  • Mermaid — diagrams from text with no server at all
  • Configuration — the full definition of params.drawio.*