<bmx-diagram>
A diagram designer: flowcharts, BPMN-style processes with swimlanes, and
network diagrams, drawn from a palette of over forty shapes. Shapes are
connected by dragging from the dot on a side; connectors route themselves
around everything in the way (elbow, straight or curved), with labels and
arrowheads. Alignment guides, a snapping grid, multiple selection, copy and
paste, undo, automatic arrangement in layers, an outline that reads the
whole diagram as text, and SVG, PNG, JSON and Mermaid out. A Mermaid
flowchart pasted in, or set in mermaid, becomes an editable diagram.
11 properties · 3 events · 22 methods · 5 parts
Example
Read-only, with shapes you can open
Click a device.
Two copies kept in step
Each change is a short list of operations. Here they go straight from one copy to the other; between people they would go over your own connection.
Show markup
<bmx-diagram
id="ex-diagram"
label="Order process"
style="--bmx-diagram-height: 36rem"
mermaid="flowchart LR
subgraph customer [Customer]
start([Order placed]) --> pay[/Card payment/]
end
subgraph shop [Shop]
pay --> check{Paid?}
check -->|Yes| pick[Pick and pack]
check -->|No| remind[Send a reminder] -.-> pay
end
subgraph courier [Courier]
pick --> ship[Deliver] --> done([Delivered])
end"
></bmx-diagram>
<div class="row" style="margin-block-start: 0.75rem; gap: 0.5rem; flex-wrap: wrap">
<bmx-button variant="outline" tone="neutral" id="ex-diagram-mermaid">Show as Mermaid</bmx-button>
<bmx-button variant="outline" tone="neutral" id="ex-diagram-png">Download PNG</bmx-button>
</div>
<pre class="note" id="ex-diagram-out" style="white-space: pre-wrap"></pre>
<h3>Read-only, with shapes you can open</h3>
<bmx-diagram id="ex-network" readonly label="Office network" style="--bmx-diagram-height: 22rem"></bmx-diagram>
<p class="note" id="ex-network-out">Click a device.</p>
<h3>Two copies kept in step</h3>
<p class="note">Each change is a short list of operations. Here they go straight from one copy to the other; between people they would go over your own connection.</p>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: 0.75rem">
<bmx-diagram id="ex-left" label="First copy" shapes="flowchart" style="--bmx-diagram-height: 24rem"></bmx-diagram>
<bmx-diagram id="ex-right" label="Second copy" shapes="flowchart" style="--bmx-diagram-height: 24rem"></bmx-diagram>
</div>
<script type="module">
await customElements.whenDefined('bmx-diagram');
const diagram = document.getElementById('ex-diagram');
const out = document.getElementById('ex-diagram-out');
document.getElementById('ex-diagram-mermaid').addEventListener('click', async () => (out.textContent = await diagram.toMermaid()));
document.getElementById('ex-diagram-png').addEventListener('click', () => diagram.download('png', 'order-process'));
const network = document.getElementById('ex-network');
const device = (id, shape, x, y, text, tone) => ({ id, shape, x, y, width: 64, height: 64, text, tone });
network.diagram = {
nodes: [
device('internet', 'internet', 40, 120, 'Internet', 'blue'),
device('firewall', 'firewall', 200, 120, 'Firewall', 'red'),
device('switch', 'switch', 360, 120, 'Core switch'),
device('web', 'server', 520, 20, 'Web server', 'green'),
device('db', 'database-server', 520, 120, 'Database', 'green'),
device('wifi', 'wireless', 520, 220, 'Wi-Fi'),
device('laptop', 'laptop', 680, 220, 'Laptops'),
],
edges: [
{ from: 'internet', to: 'firewall', endArrow: 'none' },
{ from: 'firewall', to: 'switch', endArrow: 'none' },
{ from: 'switch', to: 'web', endArrow: 'none' },
{ from: 'switch', to: 'db', endArrow: 'none' },
{ from: 'switch', to: 'wifi', endArrow: 'none' },
{ from: 'wifi', to: 'laptop', endArrow: 'none', dashed: true },
],
};
network.addEventListener('bmxDiagramNodeClick', e => (document.getElementById('ex-network-out').textContent = `Opened ${e.detail.node.text}.`));
const left = document.getElementById('ex-left');
const right = document.getElementById('ex-right');
await left.loadMermaid('flowchart TD\n a([Idea]) --> b[Draft] --> c{Approved?}\n c -->|Yes| d([Publish])\n c -->|No| b');
await right.setDiagram(await left.getDiagram());
for (const [from, to] of [[left, right], [right, left]]) from.addEventListener('bmxDiagramChange', e => to.applyOps(e.detail.ops));
</script>
The diagram is plain JSON (diagram), and every change is reported as a
list of operations (bmxDiagramChange) that another copy applies with
applyOps - the transport between people editing together is yours.
Nothing is sent anywhere by the element itself.
With readonly it shows a diagram to read, pan and zoom, and reports
shapes the reader opens (bmxDiagramNodeClick).
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
connector |
connector |
BmxDiagramRoute |
'orthogonal' |
How new connectors are drawn. |
diagram |
diagram |
Partial<BmxDiagramData> | string |
— | The diagram: nodes, edges and lanes. JSON in markup. Kept up to date as it is edited. |
grid |
grid |
number |
20 |
The grid spacing; 0 hides it. |
label |
label |
string |
— | What the diagram is, for screen readers. |
mermaid |
mermaid |
string |
— | A Mermaid flowchart to start from, when diagram is empty. |
readonly |
readonly |
boolean |
false |
Show the diagram to read, pan and zoom, without editing. |
shapes |
shapes |
readonly BmxDiagramShapeCategory[] | string |
['flowchart', 'basic', 'bpmn', 'network'] |
The shape groups in the palette, in order: any of flowchart, basic, bpmn, network. |
snap |
snap |
boolean |
true |
Shapes snap to the grid as they move. |
strings |
strings |
Partial<BmxDiagramStrings> | string |
— | Words the designer shows or says: any of BmxDiagramStrings. JSON in markup. |
toolbar |
toolbar |
boolean |
true |
Show the command bar. |
validateConnection |
property only | BmxDiagramConnectionCheck |
— | Decides whether two nodes may be connected. |
Events
| Event | Detail | Description |
|---|---|---|
bmxDiagramChange |
BmxDiagramChangeDetail |
The diagram changed. ops turn the previous diagram into this one. |
bmxDiagramNodeClick |
BmxDiagramNodeDetail |
A shape was opened: clicked in a read-only diagram, or Enter on it. |
bmxDiagramSelect |
BmxDiagramSelectDetail |
The selection changed. |
Methods
| Method | Signature | Description |
|---|---|---|
addEdge |
addEdge(edge: Partial<BmxDiagramEdge> & { from: BmxDiagramEnd | string; to: BmxDiagramEnd | string; }) => Promise<string | null> |
Connects two nodes. Resolves with the connector's id, or null if refused. |
addNode |
addNode(node: Partial<BmxDiagramNode>) => Promise<string> |
Adds a node. Give at least shape; it is placed in view if x and y are left out. Resolves with its id. |
applyOps |
applyOps(ops: readonly BmxDiagramOp[]) => Promise<void> |
Applies changes made somewhere else - operations from another copy's bmxDiagramChange. They are not added to this copy's undo, and raise no change event here. |
arrange |
arrange(direction?: BmxDiagramDirection) => Promise<void> |
Arranges the diagram in layers, top to bottom (TB) or left to right (LR). Lanes keep their nodes. |
clear |
clear() => Promise<void> |
Removes everything. Undo can bring it back. |
download |
download(format?: BmxDiagramExportFormat, name?: string) => Promise<void> |
Saves the diagram as a file: svg, png, json or mermaid (.mmd). |
fit |
fit() => Promise<void> |
Zooms and scrolls to show the whole diagram. |
getDiagram |
getDiagram() => Promise<BmxDiagramData> |
The diagram, as JSON-ready data. |
getSelection |
getSelection() => Promise<string[]> |
The ids selected. |
loadMermaid |
loadMermaid(source: string, append?: boolean) => Promise<readonly string[]> |
Reads a Mermaid flowchart. With append, it goes beside what is there; otherwise it replaces it. Resolves with any lines that could not be read. |
redo |
redo() => Promise<void> |
|
removeItems |
removeItems(ids: readonly string[]) => Promise<void> |
Removes nodes, connectors or lanes by id. A node's connectors go with it. |
reveal |
reveal(id: string) => Promise<void> |
Brings a node into view and selects it. |
setDiagram |
setDiagram(diagram: Partial<BmxDiagramData> | string) => Promise<void> |
Replaces the diagram. Undo can step back from it. |
setFocus |
setFocus(options?: FocusOptions) => Promise<void> |
|
setSelection |
setSelection(ids: readonly string[]) => Promise<void> |
Selects by id. |
toBlob |
toBlob(type?: "png" | "svg", scale?: number) => Promise<Blob> |
The diagram as a PNG or SVG file. scale multiplies the PNG's size (default 2). |
toMermaid |
toMermaid() => Promise<string> |
The diagram as a Mermaid flowchart. |
toSvg |
toSvg() => Promise<string> |
The diagram as a standalone SVG document. |
undo |
undo() => Promise<void> |
|
updateItem |
updateItem(id: string, patch: Record<string, unknown>) => Promise<void> |
Changes a node, a connector or a lane by id. |
zoomTo |
zoomTo(zoom: number) => Promise<void> |
Sets the zoom (1 is actual size), about the middle of the view. |
CSS shadow parts
| Part | Description |
|---|---|
outline |
the diagram as a list. |
palette |
the shapes to drag in. |
panel |
the properties of what is selected. |
stage |
the drawing area. |
toolbar |
the row of commands. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-diagram-background |
Behind the drawing. |
--bmx-diagram-grid |
The grid's dots. |
--bmx-diagram-height |
How tall the designer is. Default 40rem. |
--bmx-diagram-line |
Connectors. |
--bmx-diagram-selection |
Selection outlines, handles and guides. |