BPMN Expanded SubProcess

21 Oct 202519 minutes to read

Overview

An expanded subprocess is a BPMN shape that represents a complex process containing multiple child processes within it. Unlike collapsed subprocesses, expanded subprocesses display their internal structure and allow users to view and interact with the child processes directly. This makes them ideal for detailed process modeling where visibility into subprocess components is essential.

The expanded subprocess automatically adjusts its size to accommodate child elements and provides a container-like behavior for organizing related BPMN activities.

Create BPMN Expanded SubProcess

To create an expanded subprocess, configure the shape asactivity and collapsed to false. Enable the AllowDrop constraint to allow child nodes to be dropped inside the expanded subprocess container.

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,NodeConstraints, Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let nodes= [ 
    {
        id: 'subProcess',
        width: 520,
        height: 250,
        offsetX: 355,
        offsetY: 230,
        constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
        shape: {
          shape: 'Activity',
          type: 'Bpmn',
          activity: {
            activity: 'SubProcess',
            subProcess: {
              collapsed: false,
            },
          },
        },
      },]
// initialize diagram component
function App() {
    return (<DiagramComponent id="container" width={'100%'} height={'600px'} 
    // Add node
    nodes={nodes}>
      <Inject services={[BpmnDiagrams]}/>
    </DiagramComponent>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,NodeModel,NodeConstraints, Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let nodes:NodeModel[]= [ 
    {
        id: 'subProcess',
        width: 520,
        height: 250,
        offsetX: 355,
        offsetY: 230,
        constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
        shape: {
          shape: 'Activity',
          type: 'Bpmn',
          activity: {
            activity: 'SubProcess',
            subProcess: {
              collapsed: false,
            },
          },
        },
      },]
// initialize diagram component
function App() {
    return (<DiagramComponent id="container" width={'100%'} height={'600px'} 
    // Add node
    nodes={nodes}>
      <Inject services={[BpmnDiagrams]}/>
    </DiagramComponent>);
}

const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Add BPMN Nodes into Expanded SubProcess

The Processesproperty is an array collection that defines the child node values for the BPMN subprocess. This allows you to programmatically specify which BPMN elements should be contained within the expanded subprocess during initialization.

The following code example demonstrates how to define child processes within an expanded subprocess:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,NodeConstraints, Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let nodes = [ 
    {
        id: 'start',
        height: 50,
        width: 50,
        margin: { left: 50, top: 50 },
        shape: { type: 'Bpmn', shape: 'Event' },
      },
      {
        id: 'subProcess',
        width: 520,
        height: 250,
        offsetX: 355,
        offsetY: 230,
        constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
        shape: {
          shape: 'Activity',
          type: 'Bpmn',
          activity: {
            activity: 'SubProcess',
            subProcess: {
              collapsed: false,
              processes: ['start'],
            },
          },
        },
      },] 
// initialize diagram component
function App() {
    return (<DiagramComponent id="container" width={'100%'} height={'600px'} 
    // Add node
    nodes={nodes}>
      <Inject services={[BpmnDiagrams]}/>
    </DiagramComponent>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,NodeConstraints,NodeModel,Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
// A node is created and stored in nodes array.
let nodes:NodeModel[] = [ 
    {
        id: 'start',
        height: 50,
        width: 50,
        margin: { left: 50, top: 50 },
        shape: { type: 'Bpmn', shape: 'Event' },
      },
      {
        id: 'subProcess',
        width: 520,
        height: 250,
        offsetX: 355,
        offsetY: 230,
        constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
        shape: {
          shape: 'Activity',
          type: 'Bpmn',
          activity: {
            activity: 'SubProcess',
            subProcess: {
              collapsed: false,
              processes: ['start'],
            },
          },
        },
      },] 
// initialize diagram component
function App() {
    return (<DiagramComponent id="container" width={'100%'} height={'600px'} 
    // Add node
    nodes={nodes}>
      <Inject services={[BpmnDiagrams]}/>
    </DiagramComponent>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Add BPMN Nodes into Expanded SubProcess at Runtime

Users can drag and drop BPMN nodes directly onto the expanded subprocess container during runtime. The expanded subprocess automatically maintains proper containment by monitoring the bounds of child elements. When a child element is resized or repositioned within the subprocess boundaries, the expanded subprocess container dynamically adjusts its size to accommodate the changes.

This interactive behavior ensures that the subprocess container always properly encompasses all its child processes while maintaining visual clarity and proper BPMN structure.

Expanded subProcess BPMN Shape

Add/Remove Process Programmatically

The expanded subprocess supports dynamic process management through dedicated methods. Use the addProcess method to add new child processes at runtime, and the removeProcess method to remove existing processes. These methods provide programmatic control over subprocess content without requiring manual manipulation.

The following example demonstrates how to implement dynamic process addition and removal:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, NodeConstraints, Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
let diagramInstance;
// A node is created and stored in nodes array.
let nodes = [
  {
    id: 'start',
    height: 50,
    width: 50,
    margin: { left: 50, top: 50 },
    shape: { type: 'Bpmn', shape: 'Event' },
  },
  {
    id: 'event2',
    height: 50,
    width: 50,
    margin: { left: 150, top: 50 },
    shape: { type: 'Bpmn', shape: 'Event', event: { type: '' } },
  },
  {
    id: 'subProcess',
    width: 520,
    height: 250,
    offsetX: 355,
    offsetY: 230,
    constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
    shape: {
      shape: 'Activity',
      type: 'Bpmn',
      activity: {
        activity: 'SubProcess',
        subProcess: {
          collapsed: false,
          processes: ['start'],
        },
      },
    },
  },
]

const addProcess = function () {
  let event = diagramInstance.nameTable['event2'];
  /**
   * parameter 1 - A process to be added
   * parameter 2 - A string representing the parent ID where the process will be added.
   */
  diagramInstance.addProcess(event, 'subProcess');
}

const removeProcess = function () {
  /**
   * parameter 1 -  The ID of the process to be removed.
   */
  diagramInstance.removeProcess('event2');
}

// initialize diagram component
function App() {
  return (<div>
    <ButtonComponent content="Add Process" onClick={addProcess} />
    <ButtonComponent content="Remove Process" onClick={removeProcess} />
    <DiagramComponent id="container" width={'100%'} height={'600px'} ref={(diagram) => (diagramInstance = diagram)}
      // Add node
      nodes={nodes}>

      <Inject services={[BpmnDiagrams]} />
    </DiagramComponent></div>);
}

const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,NodeModel,NodeConstraints, Inject, BpmnDiagrams } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
let diagramInstance:DiagramComponent;
// A node is created and stored in nodes array.
let nodes:NodeModel[] = [ 
    {
        id: 'start',
        height: 50,
        width: 50,
        margin: { left: 50, top: 50 },
        shape: { type: 'Bpmn', shape: 'Event' },
      },
      {
        id: 'event2',
        height: 50,
        width: 50,
        margin: { left: 150, top: 50 },
        shape: { type: 'Bpmn', shape: 'Event', event: { type: '' } },
      },
      {
        id: 'subProcess',
        width: 520,
        height: 250,
        offsetX: 355,
        offsetY: 230,
        constraints: NodeConstraints.Default | NodeConstraints.AllowDrop,
        shape: {
          shape: 'Activity',
          type: 'Bpmn',
          activity: {
            activity: 'SubProcess',
            subProcess: {
              collapsed: false,
              processes: ['start'],
            },
          },
        },
      },
] 

const addProcess=function() {
    let event = diagramInstance.nameTable['event2'];
    /**
     * parameter 1 - A process to be added
     * parameter 2 - A string representing the parent ID where the process will be added.
     */
    diagramInstance.addProcess(event, 'subProcess');
}

const removeProcess=function() {
  /**
   * parameter 1 -  The ID of the process to be removed.
   */
    diagramInstance.removeProcess('event2');
}

// initialize diagram component
function App() {
    return (<div>
         <ButtonComponent content="Add Process" onClick={addProcess}/>
         <ButtonComponent content="Remove Process" onClick={removeProcess}/>
        <DiagramComponent id="container" width={'100%'} height={'600px'}  ref={(diagram) => (diagramInstance = diagram)}
    // Add node
    nodes={nodes}>
        
      <Inject services={[BpmnDiagrams]}/>
    </DiagramComponent></div>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);