Pele: Render Mermaid Diagrams to SVG with JavaScript

Category: Chart & Graph , Javascript | October 20, 2026
Authorobsidianmd
Last UpdateOctober 20, 2026
LicenseMIT
Tags
Views0 views
Pele: Render Mermaid Diagrams to SVG with JavaScript

Pele is a dependency-free JavaScript library that renders Mermaid diagrams as SVG.

It handles every built-in diagram type in Mermaid and can rearrange supported layouts for narrower containers.

Pele renders synchronously, with a choice between a raw SVG string and a mounted diagram that responds to container resizing.

You can use CSS variables to control diagram colors and fonts.

Features

  • SVG output for use in HTML pages and generated content.
  • Touch, mouse, and keyboard zoom controls for large diagrams.
  • Source updates through a mounted diagram controller.
  • Diagram labels and layout spacing that adapt to narrow widths.
  • Individual diagram imports and on-demand type loading.
  • Reusable parsed diagrams for rendering at different widths.
  • Configurable input limits, error handling, and URL filtering.

How To Use It

Installation

Load the main JavaScript from a CDN. The script exposes the pele global and includes all built-in diagram types.

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/pele.global.js"></script>

Or install the package with NPM:

npm install pele

Basic Usage

Create a container and call pele.mount() with Mermaid syntax. Use a block-level container whose width does not depend on the SVG.

<div id="diagram" class="diagram-container"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/pele.global.js"></script>
<script>
  const source = `flowchart LR
    A[Mermaid source] --> B[SVG diagram]
    B --> C[Web page]`;
  pele.mount(document.getElementById('diagram'), source);
</script>

Render an SVG String with ES Modules

Use render() when an application needs an SVG string for a static preview or generated content. The function is synchronous. Match fontFamily to the CSS font used for diagram labels, especially when --pele-font is set.

import { render } from 'pele';
const source = `sequenceDiagram
  participant Client
  participant Server
  Client->>Server: Request
  Server-->>Client: Response`;
const container = document.getElementById('diagram');
const styles = getComputedStyle(container);
const fontFamily = styles.getPropertyValue('--pele-font').trim() || styles.fontFamily;
const { svg } = render(source, { fontFamily });
container.innerHTML = svg;

Update a Diagram and Handle Resizing

mount() observes container width changes, reads fonts from CSS, and returns a controller for later updates. Pending web fonts and container resizes trigger automatic redraws. Call refresh() after changing the font or moving the container. Use destroy() when you no longer need observation.

import { mount } from 'pele';
const diagram = mount(document.getElementById('diagram'), `flowchart LR
  A[Draft] --> B[Review]`);
diagram.update(`flowchart LR
  A[Draft] --> B[Review] --> C[Published]`);
// After changing the container font or moving it:
diagram.refresh();
// During component teardown:
// diagram.destroy();

For one-off render() calls, pass maxWidth when the layout needs to adapt. Your application must call render() again after a container resize. By default, supported layouts can switch direction below 640 pixels. Set autoDirection: false to preserve the direction specified in the Mermaid source.

const { svg } = render(source, {
  maxWidth: document.getElementById('diagram').clientWidth,
  autoDirection: false
});

Zoom and Pan

Mounted diagrams use zoom: 'auto' by default. Zoom becomes available when a diagram is scaled down to fit its container. Set zoom: true to enable it for every mounted diagram, or zoom: false to disable it. Controls include pinch, Ctrl/Cmd plus wheel, drag, double-click, and keyboard commands when the diagram has focus. An ordinary wheel scrolls the page.

import { mount } from 'pele';
const diagram = mount(document.getElementById('diagram'), source, {
  zoom: { always: true, maxScale: 3, controls: true }
});
// Zoom is also available from the mounted controller:
diagram.zoom?.zoomTo(1.5);

To add zoom to an SVG created with render(), use enableZoom(element, options). Call the zoom controller’s refresh() if the SVG changes.

Load Only the Diagram Types You Need

The pele entry point includes all diagram types. For smaller initial bundles, use pele/core and register individual diagram modules.

import { register, render } from 'pele/core';
import flowchart from 'pele/diagrams/flowchart';
import sequence from 'pele/diagrams/sequence';
register(flowchart, sequence);
const { svg } = render('flowchart LR\n  A --> B');

For applications that receive different diagram types at runtime, pele/lazy loads each type on first use. It includes renderAsync(), mountAsync(), and load(). When updating a diagram from mountAsync() to another type, call load() for that type before update().

import { load, renderAsync } from 'pele/lazy';
await load('flowchart');
const { svg } = await renderAsync('flowchart LR\n  A --> B');

Styling and Themes

Set CSS variables on a parent element or the root SVG (.pele). Theme color changes take effect immediately. If a font changes, call refresh() to measure label widths again. Mermaid style, classDef, and linkStyle declarations can set fixed colors that do not follow CSS theme changes.

.diagram-container {
  --pele-bg: #ffffff;
  --pele-fg: #222222;
  --pele-surface: #f3f5f8;
  --pele-surface-alt: #e8edf5;
  --pele-border: #8795a5;
  --pele-line: #334155;
  --pele-accent: #2563eb;
  --pele-font: system-ui, sans-serif;
}
@media (prefers-color-scheme: dark) {
  .diagram-container {
    --pele-bg: #111827;
    --pele-fg: #f3f4f6;
    --pele-surface: #1f2937;
    --pele-surface-alt: #374151;
    --pele-border: #6b7280;
    --pele-line: #d1d5db;
    --pele-accent: #93c5fd;
  }
}

CSS Custom Properties

VariableDefault and purpose
--pele-bg#ffffff. Background color.
--pele-fg#1f1f1f. Primary text.
--pele-muted#6e6e6e. Secondary text.
--pele-line#1f1f1f. Edges and arrowheads.
--pele-surface#f3f3f3. Node fill.
--pele-surface-alt#e6e6e6. Subgraph fill.
--pele-border#8a8a8a. Node and subgraph borders.
--pele-accent#5b7bd5. Highlights.
--pele-critical#e45756. Critical Gantt tasks and high Kanban priorities.
--pele-error#e45756. Error text inside a mounted diagram.
--pele-fontMeasured font. Regular labels.
--pele-font-monoMeasured font. Monospace labels.
--pele-title-weightbold. Diagram title weight.
--pele-heading-weightbold. Section and class-heading weight.
--pele-bold-weightbold. Bold label weight.
--pele-radius4px. Rounded corners.

Series Color Variables

VariableDefault
--pele-series-1#4c78a8
--pele-series-2#f58518
--pele-series-3#54a24b
--pele-series-4#e45756
--pele-series-5#72b7b2
--pele-series-6#eeca3b
--pele-series-7#b279a2
--pele-series-8#9d755d

Zoom Control Position Variables

The zoom buttons accept --pele-zoom-top, --pele-zoom-right, --pele-zoom-bottom, and --pele-zoom-left for positioning.

Public SVG Classes

Pele exposes these SVG classes for element-level styling. Node groups also carry a data-id attribute containing the corresponding Mermaid node ID.

ClassElement
peleRoot SVG element.
pele-flowchartRoot SVG of a flowchart.
pele-titleDiagram title.
pele-nodeNode group.
pele-edgeEdge group.
pele-edge-labelEdge label.
pele-clusterSubgraph.
pele-cluster-labelSubgraph title.
pele-labelNode label text.
pele-markerArrowhead or edge marker.
pele-iconIcon.

To style the label of the Mermaid node start:

.pele-node[data-id="start"] .pele-label {
  fill: var(--pele-accent);
}

API Reference

Functions and Entry Points

APISignature or behavior
render(source, options?)Synchronously returns a RenderResult from Mermaid text or a parsed DiagramModel. Throws PeleError on failure.
mount(element, text, options?)Renders into an HTML element, observes sizing and fonts, and returns a Mounted controller.
parse(text, options?)Returns a ParsedDiagramModel for reuse in render(). Accepts limit, maxEdges, and config.
detectType(text)Returns the detected DiagramType or null, even when the type is not registered.
supports(text)Returns whether the detected type is registered or loaded. Does not validate syntax.
enableZoom(element, options?)Attaches zoom and pan to a rendered diagram and returns a Zoom controller.
register(...diagrams)Registers individual diagram modules when using pele/core.
renderAsync(source, options?)Renders with on-demand diagram type loading from pele/lazy.
mountAsync(element, text, options?)Loads and mounts a diagram from pele/lazy; returns a mounted controller asynchronously.
load(type)Loads a diagram type ahead of use from pele/lazy.

RenderOptions

OptionType, default, and purpose
measurerTextMeasurer. Browser canvas measurement or a built-in width table by default.
fontFamilystring, sans-serif. Font for regular labels.
fontFamilyMonostring, monospace. Monospace label font.
fontSizenumber, 16. Base size in pixels.
idPrefixstring. Prefix for SVG accessibility title and description IDs. Each diagram needs a unique value; mount() generates one.
responsiveboolean, true. Allows SVG to shrink to its container; set false for fixed pixel dimensions.
maxWidthnumber. Available layout width in pixels.
autoDirectionboolean, true. Allows responsive direction changes where applicable.
directionBreakpointnumber, 640. Width threshold in pixels.
nownumber | Date, current time. Reference time for Gantt charts.
paddingnumber. Diagram padding in pixels.
limitnumber, 50000. Maximum source characters.
outputLimitnumber, 4000000. Maximum SVG characters.
maxEdgesnumber, 5000. Maximum flowchart or agentflow edges.
linkSchemesstring[], ['http', 'https', 'mailto', 'tel']. Allowed URL link schemes.
imageSchemesstring[], ['http', 'https']. Allowed image URL schemes.
linkRelstring, noopener. Link rel attribute.
linksboolean, true. Allows diagram links.
imagesboolean, true. Allows diagram images.
icons(name: string) => string | null | undefined. Supplies trusted SVG markup for icons.
configobject. Default Mermaid settings; frontmatter and directives can override them.

MountOptions and Mounted Controller

MountOptions inherits every RenderOptions entry above and introduces four additional options. mount() and update() display invalid diagram source inside the container.

OptionType and behavior
onRender(result: RenderResult) => void. Called after every successful render.
onError(error: unknown) => void. Called after initial errors, failed updates, and automatic redraw failures.
zoomboolean | 'auto' | ZoomOptions, default 'auto'. Enables zoom when a diagram shrinks, always, never, or with custom settings.
sanitize(svg: string) => Node. Calls an application-supplied SVG sanitizer before insertion and uses the returned Node.
MemberPurpose
resultLatest RenderResult, or undefined before any successful render.
sourceThe last supplied Mermaid text, even if it failed.
errorMost recent failure, or undefined.
zoomZoom controller, or undefined when disabled.
update(text, options?)Updates the source and optionally replaces options. Hidden diagrams can defer redraw.
refresh()Re-renders only when container width or fonts have changed.
destroy()Stops observation and retains the SVG in the container.

ZoomOptions and Zoom Controller

OptionType and default
alwaysboolean, false. Enables zoom even when the diagram fits.
maxScalenumber, 3. Maximum zoom scale, relative to natural size 1.
controlsboolean, true. Displays zoom buttons.
labels{ zoomIn?, zoomOut?, reset? }. Button labels, English by default.
MemberPurpose
scaleCurrent scale; 1 is natural size.
fitScale at which the full diagram is visible.
zoomBy(factor)Multiplies the scale by a factor.
zoomTo(scale)Sets the zoom level.
reset()Returns to the fit scale.
refresh()Recalculates after replacing the SVG in the container.
destroy()Removes zoom behavior and resets the diagram.

RenderResult, LinkInfo, and Error Handling

render() returns an SVG string with dimensions, type information, and link details. Internal links refer to note identifiers and need application-controlled navigation.

RenderResult fieldValue
svgstring. Complete SVG markup.
widthnumber. Natural width in pixels.
heightnumber. Height in pixels.
typeDiagramType. Pele’s detected type.
mermaidTypeMermaidType. Corresponding Mermaid type.
linksLinkInfo[]. Diagram links.

Each links entry has these fields:

LinkInfo fieldValue
idIdentifier of the linked diagram element.
hrefURL for an external link or note identifier for an internal link.
internalboolean. Whether the link refers to an internal note.

PeleError extends the JavaScript Error class. Unlike mount(), render() and parse() throw for parsing or rendering failures. Error messages can contain the original diagram text. Insert error text with textContent, never innerHTML.

PeleError propertyValue
messagestring. Error text.
codestring. Error category.
typestring | null. Pele diagram type, if detected.
mermaidTypestring | null. Mermaid diagram type, if detected.
linenumber. One-based line of the problem; 0 when unavailable.
columnnumber. One-based column; 0 when unavailable.
snippetstring. Source excerpt with a column indicator, or an empty string.
Error codeMeaning
unsupported-diagramUnknown diagram type or a type that has not been registered.
syntaxInvalid diagram syntax.
semanticInvalid meaning in parsed content.
limitSource, output, nesting, or edge constraint exceeded.

For a UI that accepts arbitrary Mermaid text, catch PeleError and display the message safely:

import { PeleError, render } from 'pele';
try {
  document.getElementById('diagram').innerHTML = render(source).svg;
} catch (error) {
  if (!(error instanceof PeleError)) throw error;
  document.getElementById('diagram').textContent = error.message;
}

Diagram Types and Mermaid Compatibility

Pele accepts all built-in diagram types from Mermaid 12.1.0+.

DiagramMermaid syntax keyword
Flowchartgraph, flowchart
Swimlaneswimlane-beta
SequencesequenceDiagram
ClassclassDiagram
StatestateDiagram, stateDiagram-v2
Entity relationshiperDiagram
Ganttgantt
Git graphgitGraph
Piepie
Mindmapmindmap
Kanbankanban
Timelinetimeline
User journeyjourney
Quadrant chartquadrantChart
XY chartxychart, xychart-beta
RequirementrequirementDiagram
Sankeysankey, sankey-beta
Architecturearchitecture-beta
C4C4Context, C4Container, C4Component, C4Dynamic, C4Deployment
Blockblock, block-beta
Agentflowagentflow-beta
Railroadrailroad-beta, railroad-ebnf-beta, railroad-abnf-beta, railroad-peg-beta
Tree viewtreeView-beta
Cynefincynefin-beta
Wardley mapwardley-beta
Event modelingeventmodeling
Use caseusecase-beta
Vennvenn-beta
Ishikawaishikawa, ishikawa-beta
Packetpacket, packet-beta
Radarradar-beta
Treemaptreemap, treemap-beta
Infoinfo

Diagram Type Names in the JavaScript API

detectType() and RenderResult.type use Pele’s type names. The mermaidType field retains Mermaid’s type name for the cases where they differ.

Mermaid source keywordtypemermaidType
graph, flowchartflowchartflowchart-v2
flowchart-elkflowchartflowchart-elk
classDiagramclassclassDiagram
stateDiagramstatestateDiagram
railroad-betarailroadrailroad
railroad-ebnf-betarailroadrailroadEbnf
railroad-abnf-betarailroadrailroadAbnf
railroad-peg-betarailroadrailroadPeg

Rendering Untrusted Diagram Text

Pele escapes labels, filters styles and URLs, and limits input and SVG length. A host application must control icon markup, link navigation, Mermaid configuration, and any stricter SVG sanitization policy. The icons callback inserts the SVG markup it returns as-is. Internal link identifiers are not filtered as URLs. Images can trigger network requests when displayed. linkSchemes and imageSchemes replace the default allowed schemes, although javascript:, data:, and vbscript: are always blocked. For time limits, run rendering in a worker that the application can terminate.

To preview untrusted text without clickable links or embedded images, disable both explicitly:

const { svg } = render(source, { links: false, images: false });

Alternatives and Related Resources

You Might Be Interested In:


Leave a Reply