Skip to main content

Surface Component

To view the contents of a Toolkit's data model you need to render it. On this page we discuss rendering with the "vanilla" Toolkit, ie. not using any library integration, but the concepts discussed here are relevant to all of the library integrations.

The key piece to keep in mind is that we call render on a Toolkit instance with an object conforming to the SurfaceRenderOptions interface, and in any of the library integrations when you see a reference to "render params", that will be an object conforming to that interface (or, in some cases, an extension of the interface with minor changes to better fit with the library in question).

The return value of a render call is a Surface widget. The surface component provides a pannable/zoomable canvas in which your UI can be rendered. It has a full suite of methods to assist in configuring the display and in navigating your way around, including the ability to zoom in to specific vertices or to the entire dataset, center the display on some vertex or group of vertices, and lots more. The canvas also offers the ability to clamp its movement so that whenever a user is panning or zooming the display there is always some portion of the content visible to the user, and there are methods available to assist in mapping coordinates from the page space to the surface's viewport.


A basic example:

import { newInstance, AbsoluteLayout, EVENT_CANVAS_CLICK } from "@jsplumbtoolkit/browser-ui"

const toolkit = newInstance()
const surface = toolkit.render(someElement, {
alert("Canvas clicked.")

We render the Toolkit to "someElement", with an Absolute layout, and a click listener attached to the canvas.

Rendering options

Interface SurfaceRenderOptions

This interface defines the allowed parameters on a render call that will create a new Surface.


addToDragSelectionOnSelect?: boolean
When true, vertices that are added to the underlying Toolkit's selection will be added to the current drag selection. Prior to 5.10.2 this flag's true state was the default behaviour, but the flag now defaults to false, and the Surface uses the concept of "drag groups" to manage dragging the set of selected elements together. For more information check out the Toolkit docs, specifically the section on element dragging.
autoExitSelectMode?: boolean
Whether or not to automatically exit from 'select' mode after a lasso operation. A future version of the Toolkit will move this flag into the lasso plugin.
clamp?: boolean
Whether or not to limit the canvas movement when dragging or zooming so that some part of the dataset is always visible. Defaults to true.
clampToBackground?: boolean
When a background is in use, whether or not to clamp movement of the canvas so that some portion of the background is always visible.
clampToBackgroundExtents?: boolean
When a background is in use, whether or not to clamp movement of the canvas so that the entire background is always visible.
consumeRightClick?: boolean
Whether or not to consume right clicks, which ordinarily will cause a browser to show a context menu with some native browser functions. This defaults to true.
debug?: boolean
Defaults to false. When true, the Surface will console log a few specific pieces of activity in the lifecycle of rendering a vertex.
decorators?: Array<DecoratorSpec>
Optional list of decorators to attach to the Surface.
defaults?: JsPlumbDefaults
Optional defaults to use for the underlying renderer.
directRender?: boolean
Direct rendering is a mode in which the Surface disables pan/zoom, and adjusts its content so that the origin of the content is [0,0]. This mode can be used to embed the Surface into a read only UI (while still maintaining its dynamic connection to the underlying dataset)
dragOptions?: SurfaceDragOptions
Options for dragging vertices.
editablePaths?: boolean
If true, an EdgePathEditor will be registered on the Surface, with which you can interact via the startEditingPath(..) and stopEditingPath() methods on the Surface.
elementsDraggable?: boolean
Whether or not the elements in the Surface should be draggable. Defaults to true.
enableAnimation?: boolean
Whether or not to support animation of pan/zoom operations.
enablePan?: boolean
Whether or not to enable panning of the canvas. Defaults to true.
enhancedView?: boolean
Defaults to true, meaning node/group/edge definitions support parameters in their declarations, where the final values at render time are extracted from the data for the object being rendered.
events?: Record
Optional map of handlers for various events generated by the Surface.
Options for imposing a grid onto the elements in the Surface.
id?: string
Optional ID for the Surface. Allows you to retrieve this Surface from a toolkit instance's getRenderer(id) method.
Defines the layout to use.
logicalPorts?: boolean
Defaults to false. When true, if a port is added to a vertex programmatically, the surface treats the vertex's DOM element as the DOM element for the port if it cannot find a specific element for the port.
mode?: SurfaceMode
Mode to start in. Defaults to 'pan'.
modelEvents?: Array<>
Optional map of event handlers. Each entry consists of the event name, a CSS selector to target, and a callback function. Supplying this is equivalent to calling bindModelEvent(..) on a Surface.
modelHeightAttribute?: string
Defines the name of the attribute in a given vertex's backing data that provides its height. Defaults to "height". If you have a UI with multiple renderers you can use this parameter to store multiple sets of sizes for a given vertex inside its data.
modelLeftAttribute?: string
Defines the name of the attribute in a given vertex's backing data that provides its location in the X axis. Defaults to "left". If you have a UI with multiple renderers you can use this parameter to store multiple sets of locations for a given vertex inside its data.
modelTopAttribute?: string
Defines the name of the attribute in a given vertex's backing data that provides its location in the Y axis. Defaults to "top". If you have a UI with multiple renderers you can use this parameter to store multiple sets of locations for a given vertex inside its data.
modelWidthAttribute?: string
Defines the name of the attribute in a given vertex's backing data that provides its width. Defaults to "width". If you have a UI with multiple renderers you can use this parameter to store multiple sets of sizes for a given vertex inside its data.
Optional filter that can decide whether or not the Surface renders a specific node or group. By default all nodes and groups in the underlying dataset are rendered.
Optional function which is called at the start of panning and can return false to reject pan starting.
panWithMetaKey?: boolean
Optional, defaults to false. When true, the user must hold down the meta key (ctrl on windows) in order to pan.
plugins?: Array<SurfacePluginSpec>
Optional list of plugins to attach to the Surface.
propertyMappings?: PropertyMappings
Optional set of mappings from property values to edge definitions.
refreshAutomatically?: boolean
Whether or not the automatically refresh the layout when model data changes. Defaults to true.
refreshLayoutOnEdgeConnect?: boolean
When true, the Surface will run a refresh of the underlying layout whenever a new edge is established. This defaults to false, but you might want to set this to true if you're using the Hierarchical or Hierarchy layouts, because it has a bearing on the way they paint. However, if your users are able to drag vertices around, you may not wish for the layout to move things that they have placed, which is why this defaults to false.
relayoutOnGroupUpdate?: boolean
Defaults to false. When true, changes to a group cause the entire surface to perform a relayout.
Optional Selection - or generator - to use as the dataset to render. If you supply this the Surface will render the contents of the selection, or the list of vertices that the given function returns. This is useful for such things as inspector windows for parts of your UI.
Optional shape library that can render SVG shapes into node elements. When you provide a shape library to a surface, two things happen: 1. The surface registers a jtk-shape tag that your templates can use. The type of each node is used to extract an appropriate SVG shape definition from the shape library. 2. The 'exportToSvg()' method becomes available. Note that as of 6.5.1 SVG export is experimental, and has a few constraints/requirements - see the Toolkit docs for a discussion.
simpleEdgeStyles?: boolean
From 6.2.0, defaults to true. Prior versions default this flag to false. Instructs the Surface to automatically extract color, lineWidth, outlineWidth and outlineColor values from the backing data for edges, and to use these to set the appearance of a connection for that edge.
storePositionsInModel?: boolean
Whether or not to store vertex positions in the middle after running a layout. Defaults to false. A future release of the Toolkit will set this flag to true by default.
templates?: Record
When using 'vanilla' Toolkit, you can provide a map of templates here rather than including them somewhere in the HTML of the page.
useModelForSizes?: boolean
Defaults to false. When true, newly created nodes are sized according to values in their backing data, using the modelWidthAttribute and modelHeightAttribute as keys.
Mappings of vertex/edge types to their rendering and behaviour.
wheel?: SurfaceWheelOptions
Options for the behaviour of the mousewheel (which also covers two finger scrolling on a mac trackpad)
zoom?: number
Starting zoom for the Surface. Defaults to 1.
zoomRange?: ZoomRange
The zoom range for the Surface - minimum and maximum values, expressed as decimals. Defaults to [0.05, 3].
zoomToFit?: boolean
If true, zoom the display so that the dataset is entirely visible after initialisation.
zoomToFitIfNecessary?: boolean
If true, zoom the display so that the dataset is entirely visible after initialisation, but only adjust the zoom level if the dataset is not already visible at the default zoom level.


Event listeners can be bound to the surface widget in one of three ways:

  • via the bind method
  • in the events parameter to a render call on an instance of the Toolkit
  • in the individual Node, Group, Port and Edge definitions in the view parameter to a render call.

The full list of bindable events is listed on the events page.

Using bind

const surface = toolkitInstance.render(someElement, {

surface.bind("canvasClick", (e) => {
console.log("click on the canvas");

surface.bind("node:added", (params) => {


Declarative binding

const surface = toolkitInstance.render(someElement, {
canvasClick:(e) => {
console.log("click on the canvas");
"node:added":(params) => {}

Each of the entries in the events block is equivalent to first instantiating the surface and then calling bind on it.

Suspending Events

You can suspend/enable events from the surface widget with this method:


You can also wrap the underlying Toolkit's batch command (which runs a series of operations without making any rendering changes) with the surface widget's batch command:

surface.batch(() => {
toolkit.addNode({source:"foo", target:"bar"});

This is equivalent to:

toolkit.batch(() => {
toolkit.addNode({source:"foo", target:"bar"});

Selecting vertices

Vertices managed by a surface widget may be "selected" at any point in time programmatically via the associated toolkit instance. When a node is selected, the surface is informed, and its DOM element is assigned the class jtk-surface-selected-element.

You can also select nodes using the mouse, with a "lasso". To switch into this mode, call setMode:


In order to use the lasso, you need to install the lasso plugin. Checkout the linked page for information about how to configure the lasso.

Exiting Select Mode

Ordinarily, the surface will jump back into pan mode from select mode after some nodes have been selected, but this behaviour can be overridden, using the autoExitSelectMode flag:

const surface = toolkit.render(someElement, {


This is a full list of CSS classes used by the surface widget.

jtk-surfaceAssigned to an element that is acting as a surface widget
jtk-surface-touch-deviceAssigned to an element that is acting as a surface widget when the device supports touch events
jtk-surface-pointer-deviceAssigned to an element that is acting as a surface widget when the device supports pointer events
jtk-surface-direct-renderAssigned to an element that is acting as a surface widget in "direct render" mode, ie. readonly.
jtk-surface-nopanAssigned to a surface for which enablePan was set to false in the render args
jtk-surface-canvasAssigned to the work area of a surface widget. This canvas element will have been created automatically by the surface and is not normally something you will need to style. If you do attach some styles, you should be careful to ensure that this element always has position:relative; set.
jtk-surface-lassoAssigned to the "lasso" element used when selecting elements in a surface using the mouse.
jtk-surface-panAssigned to all of the pan buttons in a surface, regardless of which direction they control
jtk-surface-pan-topAssigned to the pan button that appears on the top edge of the surface.
jtk-surface-pan-leftAssigned to the pan button that appears on the topleft edge of the surface.
jtk-surface-pan-rightAssigned to the pan button that appears on the right edge of the surface.
jtk-surface-pan-bottomAssigned to the pan button that appears on the bottom edge of the surface.
jtk-surface-selected-elementAssigned to any element that is part of some surface's current selection.
jtk-lassoAssigned to the selection lasso element


Consuming Right Click

The default behaviour is to consume any right-click events. This is good when your app is in production, and sometimes really annoying when you're in the middle of development. To suppress this behaviour, set consumeRightClick:

var surface = toolkit.render(someElement, {

Direct Rendering

Direct rendering is a mode in which the Surface disables panning, zooming and dragging and automatically adjusts the display so that every node is visible within the viewport. You can use this mode to embed a diagram in a page, and what's super cool about it is that the diagram is "live" - any changes to the dataset will be reflected in the UI.

The diagram is inside a div with a fixed width of 350px and is floated left. Text can flow alongside the diagram. We can also manipulate the contents of the diagram without disrupting the flow of the page - click to add a new node.

Did you click it? Notice how the new node was added and the diagram was adjusted to ensure everything is still visible. If the size of the container changes the diagram will also adapt - to change the width of the container.

In direct render mode the Toolkit will render the contents of the dataset into the container you specify, honouring the dimensions of that container as determined by the page layout.


Switching on direct rendering requires that you pass a directRender flag to the parameters used to construct the surface:

import { newInstance } from '@jsplumbtoolkit/browser-ui"

const tk = newInstance()
const surface = tk.render(someContainer, {
view:{ ... },

The Surface does not disable event handlers when in direct render mode. So if you have mapped any events on specific nodes or edges, or on the canvas itself, these handlers will still be registered.


A surface in direct render mode will have the css class jtk-surface-direct-render assigned to the container into which the surface was rendered. The default stylesheet that ships with the toolkit has a rule for this class:

.jtk-surface-direct-render {

This rule takes into account that the content on the surface canvas is positioned and zoomed to fill up as much of the container as possible, right to the edge of the container. If you have elements with borders or outlines this rule will ensure the borders/outlines are not truncated when their element is right on the edge of the container.

If you do not include the toolkit's default stylesheet you may wish to consider adding this rule to your own CSS.

Zoom Limits

In direct render mode, the surface does not restrict zoom to whatever levels zooming would otherwise be restricted to.

See also

The surface widget offers a great deal of functionality, far more than can be comfortable captured in a single page. Some suggestipns for further reading are:


Views are how the surface knows what to render for each item in the data model. A solid understanding of views is key to getting the most out of the Toolkit.


If you're using the vanilla Toolkit package you'll want to familiarize yourself with the Toolkit's templates package.

Configuring connectivity

Whether you're using a library integration or not, you'll want to know about configuring connectivity in your UI - marking up your HTML to provide hints to the Toolkit about how elements can be connected to other elements.


The surface widget supports a range of different plugins - a miniview, a drag group manager, backgrounds, etc.

Element dragging

There is a fine-grained API for managing element dragging, including the support for grids and custom containment

The surface offers a number of useful methods to allow you to navigate your way around the canvas - focusing on specific elements, finding elements near to some element, panning, zooming, etc.

Shape libraries

If you're building a UI in which you want to use SVG shapes for your nodes - perhaps some kind of diagram editor - then you might want to take a look at Shape libraries - a set of named shapes that you will use to render SVG inside the vertices in your application.

SVG/PNG/JPG export

For UIs built with a shape library, the Toolkit now offers export to SVG, PNG or JPG