The example to end all examples.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

Custom Elements in bpmn-js

An example of how to support custom elements in bpmn-js while ensuring BPMN 2.0 compatibility.


📓 We refer to custom elements as elements with their own representation and data.


This example covers the following topics:

Extending the BPMN Model

The custom element is actually a BPMN task with a custom attribute. The custom attribute is defined as a moddle extension in resources/emoji.json:

  "name": "EmojiTask",
  "extends": [ "bpmn:Task" ],
  "properties": [
      "name": "emoji",
      "isAttr": true,
      "type": "String"

The XML of the custom element looks like this:

<bpmn:task id="Task_1" emojis:emoji="🤗" />

Still valid BPMN 2.0.

We could store more complex data inside the <bpmn:extensionElements /> tag. To do this, we would define the emoji as an extension element:

  "name": "Emoji",
  "superClass": [ "Element" ],
  "properties": [
      "name": "emoji",
      "isBody": true,
      "type": "String"

The XML would look like this:

<bpmn:task id="Task_1">

Rendering the Element

In order to render the custom element an additional renderer is used. It knows which elements to render:

EmojiRenderer.prototype.canRender = function(element) {
  if (!is(element, 'bpmn:Task')) {

  var businessObject = getBusinessObject(element);

  return businessObject.emoji;

It also knows how to render them:

EmojiRenderer.prototype.drawShape = function(parentNode, element) {
  var businessObject = element.businessObject,
      emoji = businessObject.emoji;

  var width = element.width,
      height = element.height;

  var rect = drawRect(parentNode, width, height, TASK_BORDER_RADIUS);

  svgAppend(parentNode, rect);

  var text = svgCreate('text');

  svgAttr(text, {
    x: 10,
    y: 25


  svgAppend(text, document.createTextNode(emoji));

  svgAppend(parentNode, text);

  return rect;

Creating Editor Controls

The custom element can be created like any other element, either via the palette or via the context pad. We override both to add a custom create control.


The palette contains an additional entry for creating the custom element:


  'create.emojiTask': {
    group: 'activity',
    className: 'icon-emoji',
    title: translate('Create Emoji Task'),
    action: {
      dragstart: createEmojiTask,
      click: createEmojiTask


Context Pad

The context pad contains an additional entry, too:


  'append.append-emoji-task': {
    group: 'model',
    className: 'icon-emoji',
    title: translate('Append Emoji Task'),
    action: {
      dragstart: appendEmojiTaskStart,
      click: appendEmojiTask


Run the Example

You need a NodeJS development stack with npm installed to build the project.

To install all project dependencies execute

npm install

To start the example execute

npm start

To build the example into the public folder execute

npm run all