JointJS+ Changelog v4.3.0
Overview
The main engineering focus over the past months went into shipping JointJS for React — native components and hooks that let you build JointJS diagrams the React way, no wrappers or workarounds.
Not on React? 4.3 still lands plenty on its own: tree shaking support for leander bundles, first-class HTML in magnets and highlighters, packaging and tooling upgrades, new Angular and genogram examples, and a round of core dia and ui fixes.
Introducing JointJS for React
JointJS for React is an idiomatic React API built on the JointJS engine — not a wrapper around the existing API. Components and hooks map the diagram lifecycle onto React's, so you manage graphs, papers, and elements with the same rendering and state patterns you already use across your app, with the full power of the core library behind it. Full API reference and guides: JointJS React documentation.
Dedicated repository for JointJS demos
We have created a dedicated repository for JointJS demos, which can be found at clientIO/joint-demos. This repository contains a collection of example projects that demonstrate various use cases and integrations of JointJS, including Angular, React, and other frameworks. The demos are organized into separate folders for easy navigation and exploration.
You can easily browse and scaffold these demo projects using the new @joint/cli command-line tool, which allows you to quickly set up a demo project without cloning the entire repository.
SVG export
What you see on the canvas is what you get in the file — anywhere it opens. Two new toSVG() options make exports truly self-contained: useComputedStyles: 'full' bakes every computed style onto the SVG, right down to ::before / ::after pseudo-elements, and embedFonts inlines all fonts as base-64 data URIs. The result renders pixel-perfect outside the browser, and the same options flow straight through the raster exporters toPNG() and toJPEG(). See the details.
HTML elements support for magnets and highlighters
In this version we introduced a new feature that allows HTML elements to be used as magnets and highlighters. This means that you can now use HTML elements as magnets for links, and also use them with highlighters. This opens up new possibilities for creating more interactive and visually appealing diagrams using HTML instead of SVG.
Packaging and developer tooling
With this version we have improved our packaging and developer tooling to make it easier to use JointJS+ in modern web development environments:
- Tree-shaking —
@joint/coreand@joint/plusnow include ES module entry points andsideEffectsconfiguration, enabling bundlers to eliminate unused exports. @joint/cli— a new command-line tool for browsing and scaffolding JointJS demo projects from theclientIO/joint-demosrepository without cloning the entire repo.
apps
Angular components in JointJS elements
This new example demonstrates how to integrate JointJS with Angular using custom element views that render Angular components inside the views.

You can find full guide and source code for this example in the JointJS+ demos repository.
Genogram
A genogram is an extended family tree diagram used in medicine, psychology, and social work. Beyond basic lineage, genograms encode additional information through standardized symbols — males as rectangles, females as ellipses, deceased persons marked with an X, and adopted persons shown with brackets. This app uses JointJS with the @joint/layout-directed-graph package to automatically lay out multi-generational family data.

You can access source code for this example in the JointJS+ demos repository.
HTML form ports
The HTML Form Ports demo showcases a small data-mapping application built from elements that render HTML inside a <foreignObject>. A form element has a port directly under each of its fields; interface elements (input and output) are lists of items with a port next to each row. All ports belong to a single ports group with an absolute position layout — the port coordinates are measured from the rendered HTML, so they stay aligned with the content regardless of the layout. Values propagate along the mapping links: from the input interface into the form's input fields, through the form's computed fields (filled dynamically from the input fields), and on to the output interface.

You can access source code for this example in the JointJS+ demos repository.
Microservice architecture
Microservice architecture example provides a boilerplate for modeling microservices with services, databases, and groups organized into containers, with links that intelligently route between groups.

You can access source code for this example in the JointJS+ demos repository.
format
SVG
format.SVG – new 'full' mode for useComputedStyles with pseudo-element capture and embedFonts support
The toSVG() function now accepts useComputedStyles: 'full' to copy the entire computed style of every element in the paper — including ::before and ::after pseudo-elements — directly onto the exported SVG clone as inline styles.
The previous default behaviour (diffing against browser defaults, now called 'minimal') is unchanged for callers that pass true or omit the option.
'full' is faster than 'minimal' (it skips the per-element diffing against browser defaults), but the SVG it produces is significantly larger. If you rasterize the result you get the best of both: fast export and a compact output. The raster exporters toPNG() and toJPEG() call toSVG() internally and accept the same options, so you can pass useComputedStyles: 'full' straight to them — no need to call toDataURL() yourself.
A new embedFonts boolean option fetches all font-face URLs used by the paper and embeds them as base-64 data URIs in the exported SVG, making the file fully self-contained when viewed outside the browser.
Visio
format.Visio – fix B-spline and NURBS curve conversion to SVG cubic Bézier paths
Fix two issues in the B-spline curve renderer used when importing Visio diagrams:
- Floating-point accumulation: the loop stepping (
t += step) could overshoot1.0due to floating-point rounding, silently dropping the curve's endpoint. The loop now uses integer steps (i / steps) to guarantee the endpoint is always included. - Rounding during control-point derivation: intermediate coordinates were rounded before being passed to the Bézier fitting algorithm, which compounded the error. Rounding is now deferred to the final SVG output.
format.Visio – fix segment removal index for curve deduplication
Fix an off-by-one error in the geometry-section curve deduplication logic. When removing a duplicate trailing segment, the wrong segment index was used, leaving the duplicate in place instead of removing it.
ui
Navigator
ui.Navigator – CSS-driven sizing and new getInnerSize() method
The Navigator now tracks its own DOM size via ResizeObserver and automatically recomputes the content ratio whenever the element is resized by CSS (calc(), flex, %, etc.). Previously the Navigator only recalculated on graph events, so CSS-driven resizes were ignored.
A new protected method getInnerSize() returns the inner pixel dimensions of the navigator element — the outer DOM size minus the uniform padding option — and stays accurate across CSS-driven resizes.
The width and height options now accept string values (e.g. CSS units) in addition to numbers.
Selection
ui.Selection – handle groups, getHandle(), hideOnDrag, custom className, and handle data
Several new features which mimic Halo overlay handles have been added to Selection handles:
- Handle groups (
options.groups): handles can now be organized into named position groups (e.g.'top','bottom','left','right'). Each group renders its handles using a CSS grid layout. Built-in position groups matching the default handle positions are provided by default. To enable default groups provideoptions.groups = {}. getHandle(name): retrieves a handle descriptor by name, making it easier to inspect or modify individual handles after initialization.hideOnDrag: when set on a handle, the handle is hidden during drag operations.className: an optional extra CSS class can be added to individual handle elements.- Handle data: arbitrary data can be attached to handles and read back via the existing handle event context.
ui.Selection – fix initialization logic to allow overriding getDefaultHandle static method in subclasses
Fix an issue where the Selection constructor wasn't calling the static getDefaultHandle() method during initialization, preventing subclasses from overriding the default handle definitions.
ui.SelectionWrapper – expose overridable DEFAULT_VISIBILITY class property
SelectionWrapper now declares a DEFAULT_VISIBILITY class property (default: true) that controls whether the selection wrapper is shown by default when a selection exists.
Previously the fallback value was hardcoded to true inside shouldBeVisible(). It can now be overridden by a subclass to change the default without replacing the full method:
class HiddenByDefaultWrapper extends SelectionWrapper {
DEFAULT_VISIBILITY = false;
}
Halo
ui.Halo – fix initialization logic to allow overriding getDefaultHandle static method in subclasses
Fix an issue where the Halo constructor wasn't calling the static getDefaultHandle() method during initialization, preventing subclasses from overriding the default handle definitions.
FreeTransform
ui.FreeTransform – fix flicker caused by deferred paper transform update
Fix a visual flicker that occurred when the paper's transform changed (e.g. during zoom) while a FreeTransform widget was active. The widget now synchronously updates its position when the paper transform changes, eliminating the one-frame delay.
Snaplines
ui.Snaplines – correct filter callback signature to receive elementView
The filter callback option now receives the elementView being dragged as its second argument:
filter: string[] | dia.Cell[] | ((this: Snaplines, targetElement: dia.Element, elementView: dia.ElementView) => boolean);
Previously the callback only received the candidate snap target (targetElement), making it impossible to apply per-dragged-element filtering logic (e.g. hiding snap guides when dragging specific element types). The dragging elementView is now passed so filters can make decisions based on both the candidate and the dragging element.
PaperScroller
ui.PaperScroller – fix text selection during panning
Fix an issue where starting a blank-drag pan could trigger native browser text or element selection.
In Firefox in particular, this selection would autoscroll the container when the pointer approached a scrollbar or the edge of the viewport, causing the paper to drift in the opposite direction to the user's pan gesture. The fix temporarily sets user-select: none on the scroller element for the duration of the pan and restores the previous value when panning ends.
Stencil
ui.Stencil – overridable paper constructors for group and drag papers
Two new overridable class properties have been added to Stencil:
PAPER_GROUP_CONSTRUCTOR— the constructor used when creating the internaldia.Paperfor each stencil group (and for the single ungrouped paper).PAPER_DRAG_CONSTRUCTOR— the constructor used when creating the transient drag paper.
Both default to dia.Paper. Extending Stencil and overriding these properties allows you to substitute a custom Paper subclass — for example, a React-aware paper — without overriding the full stencil rendering logic.
layout
TreeLayout
layout.TreeLayout – support nested property paths in attributeNames
The attributeNames option of TreeLayout now resolves values with element.prop() instead of element.get().
This means attributes like offset, margin, prevSiblingGap, nextSiblingGap, siblingRank, firstChildGap, and layout can now be stored at nested paths (e.g. 'custom/layout') rather than only at top-level model attributes.
StackLayout
layout.StackLayout – support nested attribute paths for stackIndex properties
StackLayout now uses element.prop() and element.prop(path, value) instead of element.get() / element.set() when reading and writing the stackIndexAttributeName and stackElementIndexAttributeName attributes.
Nested paths (e.g. 'stack/index') are now supported for both properties.
dia
Paper
dia.Paper – originX / originY options for getFitToContentArea()
Two new options — originX and originY — can be passed to paper.getFitToContentArea() to shift the grid anchor to a specific paper-local coordinate before the fit rectangle is computed. The returned Rect is translated back into absolute coordinates so callers receive a result consistent with the rest of the paper coordinate system.
When omitted, both default to 0, reproducing the previous behavior exactly.
dia.Paper / dia.Graph – typed EventMap for IDE autocomplete on on() calls
New exported types dia.Paper.EventMap and dia.Graph.EventMap map every built-in event name to its handler signature. paper.on(…) and graph.on(…) now produce IDE autocomplete suggestions and compile-time checks on event names and callback arguments. Untyped string calls continue to compile unchanged via a fallback overload.
dia.Paper – new getCellView() method for strict view lookup
A new paper.getCellView(cell) method returns the CellView instance for a cell only if it has already been instantiated. Unlike paper.findViewByModel(), it does not resolve placeholder views and does not schedule any rendering updates — making it safe to call from pointer-event handlers or during virtual rendering:
const cellView = paper.getCellView(cell);
if (cellView) {
// cell is currently rendered — safe to inspect the DOM
}
Returns null if no real view exists for the cell (e.g. the cell is outside the virtual rendering viewport or has not been rendered yet).