Ports in React Diagram

21 Aug 202624 minutes to read

Ports are specialized connection points on nodes that provide precise control over where connectors attach. Unlike node-to-node connections that automatically adjust their attachment points, ports maintain fixed connection locations even when nodes are moved, rotated, or resized. This makes ports essential for creating stable, predictable diagram layouts and professional flowcharts.

Port

Types of Connections

The Diagram component supports two distinct connection methods, each serving different use cases depending on the level of connection control required.

Node to Node Connection

Node to node connections automatically find the optimal attachment point on a node’s boundary. When either connected node moves, the connector dynamically repositions to maintain the shortest path between nodes. This connection type works best for simple diagrams where precise connection points are not critical.

When a connector is connected between two nodes, its end points are automatically docked to the node’s nearest boundary as shown in the following gif.

Node to Node

Port to Port Connection

Port to port connections attach to specific, predefined points on nodes. These connections remain fixed to their designated ports regardless of node movement, ensuring consistent diagram appearance and reliable connector behavior. This connection type is ideal for technical diagrams, flowcharts, and any scenario requiring precise connector placement.

Port to port

For details on how to create ports, see Create Port.

Create Port

Before adding ports, ensure the Diagram component is rendered and the required modules are injected. For setup details, see Getting Started and Module Injection.

Ports are defined as objects within a node’s ports collection. The offset property accepts fractional values (0 to 1) that determine the port’s position relative to the node’s bounds, where (0,0) represents the top-left corner and (1,1) represents the bottom-right corner.

The following code demonstrates how to add ports during node initialization:

import * as React from "react";
import * as ReactDOM from "react-dom";
import {DiagramComponent, PortVisibility} from "@syncfusion/ej2-react-diagrams";

let node = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    // Initialize port collection
    ports: [{
        // Sets the position for the port
        offset: {
            x: 0.5,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    }]
}];
// initialize Diagram component
function App() {
  return (
    <DiagramComponent
      id="container"
      width={'100%'}
      height={'600px'}
      nodes={node}
      // render initialized Diagram
    />
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import {DiagramComponent, PortVisibility, NodeModel} from "@syncfusion/ej2-react-diagrams";

let node: NodeModel[] = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    // Initialize port collection
    ports: [{
        // Sets the position for the port
        offset: {
            x: 0.5,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    }]
}];
// initialize Diagram component
function App() {
  return (
    <DiagramComponent
      id="container"
      width={'100%'}
      height={'600px'}
      nodes={node}
      // render initialized Diagram
    />
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

NOTE

When setting a Port’s ID, ensure that it does not contain white spaces, does not start with a number or special character, and does not include special characters such as underscores (_).

Add Ports at Runtime

The addPorts method enables dynamic port creation after the diagram has been initialized. This functionality is useful for interactive applications where users can customize node connection points or when ports need to be added based on business logic.

The port’s ID property defines a unique identifier that can be used to reference the port in subsequent operations. If no ID is specified, the system automatically generates a default ID.

Use the addPorts method with the following signature: addPorts(node: NodeModel, ports: PointPortModel[]). The following example adds a new port to an existing node:

import * as React from "react";
import * as ReactDOM from "react-dom";
import {DiagramComponent,PortVisibility} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance;

let node = [{
  offsetX: 250,
  offsetY: 250,
  width: 100,
  height: 100,
}];

let port = [{
  id: 'port1',
  offset: {
    x: 0,
    y: 0.5
  },
  visibility: PortVisibility.Visible
}, {
  id: 'port2',
  offset: {
    x: 1,
    y: 0.5
  },
  visibility: PortVisibility.Visible
},
{
  id: 'port3',
  offset: {
    x: 0.5,
    y: 0
  },
  visibility: PortVisibility.Visible
},
{
  id: 'port4',
  offset: {
    x: 0.5,
    y: 1
  },
  visibility: PortVisibility.Visible
}];

// Method to add ports through run time
const addport = () => {
  // Parameters:
  // - node: The node to which the port will be added.
  // - port: The port collection to be added to the node.
  diagramInstance.addPorts(diagramInstance.nodes[0], port);
}

// initialize Diagram component
function App() {
  return (
    <div>
      <ButtonComponent content="Add Port" onClick={addport} />
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      // render initialized Diagram
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import {Diagram, DiagramComponent,PortVisibility,   NodeModel,PointPortModel,} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance:DiagramComponent;

let node: NodeModel[] = [{
  offsetX: 250,
  offsetY: 250,
  width: 100,
  height: 100,
}];

let port: PointPortModel[] = [{
  id: 'port1',
  offset: {
    x: 0,
    y: 0.5
  },
  visibility: PortVisibility.Visible
}, {
  id: 'port2',
  offset: {
    x: 1,
    y: 0.5
  },
  visibility: PortVisibility.Visible
},
{
  id: 'port3',
  offset: {
    x: 0.5,
    y: 0
  },
  visibility: PortVisibility.Visible
},
{
  id: 'port4',
  offset: {
    x: 0.5,
    y: 1
  },
  visibility: PortVisibility.Visible
}];

// Method to add ports through run time
const addport = () => {
  // Parameters:
  // - node: The node to which the port will be added.
  // - port: The port collection to be added to the node.
  diagramInstance.addPorts(diagramInstance.nodes[0], port);
}

// initialize Diagram component
function App() {
  return (
    <div>
      <ButtonComponent content="Add Port" onClick={addport} />
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={node}
      // render initialized Diagram
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Remove Ports at Runtime

The removePorts method allows dynamic removal of ports from nodes. When a port is removed, any connectors attached to that port are automatically disconnected. This method is particularly useful for creating adaptive interfaces or cleaning up unused connection points. If the specified port ID does not exist on the target node, the removePorts call is ignored and no exception is thrown.

Use the removePorts method with the following signature: removePorts(node: NodeModel, portIds: string[]). The following example removes a port by its ID:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, PortVisibility } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance;

let node = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    // Initialize port collection
    ports: [{
        id: 'port1',
        offset: {
            x: 0,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port2',
        offset: {
            x: 1,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port3',
        offset: {
            x: 0.5,
            y: 0
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port4',
        offset: {
            x: 0.5,
            y: 1
        },
        visibility: PortVisibility.Visible
    }
    ]
}];
// initialize Diagram component
let ports = [{
    id: 'port1',
}, {
    id: 'port2',
}, {
    id: 'port3',
}, {
    id: 'port4',
}];

// Method to add ports through run time
const removePort = () => {
    // Parameters:
    // - node: The node from which the ports will be removed.
    // - ports: The collection of ports to be removed from the node.
    diagramInstance.removePorts(diagramInstance.nodes[0], ports);
}

function App() {
    return (
        <div>
            <ButtonComponent content="Remove Port" onClick={removePort} />
            <DiagramComponent id="container" ref={(diagram) => (diagramInstance = diagram)} width={'100%'} height={'600px'} nodes={node} />
        </div>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, PortVisibility,NodeModel } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance: DiagramComponent;

let node: NodeModel[] = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    // Initialize port collection
    ports: [{
        id: 'port1',
        offset: {
            x: 0,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port2',
        offset: {
            x: 1,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port3',
        offset: {
            x: 0.5,
            y: 0
        },
        visibility: PortVisibility.Visible
    },
    {
        id: 'port4',
        offset: {
            x: 0.5,
            y: 1
        },
        visibility: PortVisibility.Visible
    }
    ]
}];

// initialize Diagram component
let ports = [{
    id: 'port1',
}, {
    id: 'port2',
}, {
    id: 'port3',
}, {
    id: 'port4',
}];

// Method to add ports through run time
const removePort = () => {
    // Parameters:
    // - node: The node from which the ports will be removed.
    // - ports: The collection of ports to be removed from the node.
    diagramInstance.removePorts(diagramInstance.nodes[0], ports);
}

function App() {
    return (
        <div>
            <ButtonComponent content="Remove Port" onClick={removePort} />
            <DiagramComponent id="container" ref={(diagram) => (diagramInstance = diagram)} width={'100%'} height={'600px'} nodes={node} />
        </div>);
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Update Port at Runtime

Unlike addPorts and removePorts, port updates do not use a dedicated method. Modify the port object directly, and then call diagram.dataBind() to apply the changes. This approach enables dynamic customization of port appearance, position, and behavior based on application state or user interactions.

The following code example illustrates how to change the port offset at runtime.

import * as React from "react";
import * as ReactDOM from "react-dom";
import {DiagramComponent,PortVisibility} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance;


let node = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    ports: [{
        offset: {
            x: 0.5,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    }]
}];
 
// Method to update ports at run time
const updatePort = () => {
    diagramInstance.nodes[0].ports[0].offset = {
        x: 1,
        y: 1
    };
    diagramInstance.dataBind();
  }

// initialize Diagram component
function App() {
  return (
    <div>
    <ButtonComponent content="update Port" onClick={updatePort} />
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={node}
    />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import {DiagramComponent,PortVisibility,NodeModel} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance: DiagramComponent;


let node: NodeModel[] = [{
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    ports: [{
        offset: {
            x: 0.5,
            y: 0.5
        },
        visibility: PortVisibility.Visible
    }]
}];
 
// Method to update ports at run time
const updatePort = () => {
    diagramInstance.nodes[0].ports[0].offset = {
        x: 1,
        y: 1
    };
    diagramInstance.dataBind();
  }

// initialize Diagram component
function App() {
  return (
    <div>
    <ButtonComponent content="update Port" onClick={updatePort} />
    <DiagramComponent
      id="container"
      ref={(diagram) => (diagramInstance = diagram)}
      width={'100%'}
      height={'600px'}
      nodes={node}
    />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Specify Connection Direction to Port

The connectionDirection property controls the side of a port from which connections are allowed. It accepts Auto, Left, Right, Top, or Bottom. This feature is useful for controlling connector routing in technical diagrams.

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, PortVisibility,PortConnectionDirection } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance;

var nodes = [
    {
      id: 'node1',
      offsetX: 450,
      offsetY: 200,
      width: 100,
      height: 100,
      ports: [
        {
          id: 'port1',
          offset: { x: 0, y: 0 },
          visibility: PortVisibility.Visible,
        },
      ],
    },
    {
      id: 'node2',
      offsetX: 270,
      offsetY: 300,
      width: 100,
      height: 100,
      ports: [
        {
          id: 'port3',
          offset: { x: 0.5, y: 0.5 },
          visibility: PortVisibility.Visible,
          //Sets the connection direction as Left
          connectionDirection: 'Left',
        },
      ],
    },
  ];
  //initialize the connector to connect the nodes
let connectors = [
    {
        id: 'connector1',
        type: 'Orthogonal',
        sourceID: 'node2',
        targetID: 'node1',
        sourcePortID: 'port3',
        targetPortID: 'port1',
}];

// Method to add ports through run time
const changeConnectionDirection = () => {
    diagramInstance.nodes[1].ports[0].connectionDirection='Top'
  }

function App() {
    return (
        <div>
          <ButtonComponent content="Change Connection Direction" onClick={changeConnectionDirection} />
          <DiagramComponent
            id="container"
            ref={(diagram) => (diagramInstance = diagram)}
            width={'100%'}
            height={'600px'}
            nodes={nodes}
            connectors={connectors}
          // render initialized Diagram
          />
        </div>
      );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent, PortVisibility,NodeModel,ConnectorModel } from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance: DiagramComponent;

var nodes:NodeModel[] = [
    {
      id: 'node1',
      offsetX: 450,
      offsetY: 200,
      width: 100,
      height: 100,
      ports: [
        {
          id: 'port1',
          offset: { x: 0, y: 0 },
          visibility: PortVisibility.Visible,
        },
      ],
    },
    {
      id: 'node2',
      offsetX: 270,
      offsetY: 300,
      width: 100,
      height: 100,
      ports: [
        {
          id: 'port3',
          offset: { x: 0.5, y: 0.5 },
          visibility: PortVisibility.Visible,
          //Sets the connection direction as Left
          connectionDirection: 'Left',
        },
      ],
    },
  ];

let connectors: ConnectorModel[] = [
    {
        id: 'connector1',
        type: 'Orthogonal',
        sourceID: 'node2',
        targetID: 'node1',
        sourcePortID: 'port3',
        targetPortID: 'port1',
}];

// Method to add ports through run time
const changeConnectionDirection = () => {
    diagramInstance.nodes[1].ports[0].connectionDirection='Top'
  }

function App() {
    return (
        <div>
          <ButtonComponent content="Change Connection Direction" onClick={changeConnectionDirection} />
          <DiagramComponent
            id="container"
            ref={(diagram) => (diagramInstance = diagram)}
            width={'100%'}
            height={'600px'}
            nodes={nodes}
            connectors={connectors}
          // render initialized Diagram
          />
        </div>
      );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

connectionDirection

InEdges and OutEdges of Ports

Each port maintains collections of its connected connectors through read-only properties. The inEdges property contains the IDs of all connectors that terminate at the port, while outEdges contains the IDs of connectors that originate from the port. These properties are automatically maintained by the diagram and provide valuable information for traversing connection relationships.

The inEdges and outEdges of the port are read-only and cannot be customized.

The following code example shows how to get inEdges and outEdges of a port:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,PortVisibility} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance;

let nodes = [
  {
    id: 'node1',
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    ports: [
      {
        id: 'port1',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
      {
        id: 'port2',
        offset: { x: 0.5, y: 0 },
        visibility: PortVisibility.Visible,
      },
    ],
  },
  {
    id: 'node2',
    offsetX: 250,
    offsetY: 400,
    width: 100,
    height: 100,
    ports: [
      {
        id: 'port3',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
      {
        id: 'port4',
        offset: { x: 0.5, y: 1 },
        visibility: PortVisibility.Visible,
      },
    ],
  },
];

let connectors = [
  {
    id: 'connector1',
    sourceID: 'node1',
    targetID: 'node2',
    type: 'Orthogonal',
    sourcePortID: 'port1',
    targetPortID: 'port3',
    annotations: [{ content: 'connector1' }],
  },
  {
    id: 'connector2',
    sourceID: 'node2',
    targetID: 'node1',
    type: 'Orthogonal',
    sourcePortID: 'port4',
    targetPortID: 'port2',
    annotations: [{ content: 'connector2' }],
  },
];


// Method for inEdges
const inEdges = () => {
  let port1 = diagramInstance.nodes[0].ports[1];
  console.log(port1.inEdges[0]);
}

// Method for outEdges
const outEdges = () => {
  let port1 = diagramInstance.nodes[0].ports[0];
  console.log(port1.outEdges[0]);
}

// initialize Diagram component
function App() {
  return (
    <div>
      <ButtonComponent content="In Edges" onClick={inEdges} />
      <ButtonComponent content="Out Edges" onClick={outEdges} />
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={nodes}
        connectors={connectors}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);
import * as React from "react";
import * as ReactDOM from "react-dom";
import { DiagramComponent,PortVisibility, ConnectorModel, NodeModel} from "@syncfusion/ej2-react-diagrams";
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';

let diagramInstance: DiagramComponent;

let nodes: NodeModel[] = [
  {
    id: 'node1',
    offsetX: 250,
    offsetY: 250,
    width: 100,
    height: 100,
    ports: [
      {
        id: 'port1',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
      {
        id: 'port2',
        offset: { x: 0.5, y: 0 },
        visibility: PortVisibility.Visible,
      },
    ],
  },
  {
    id: 'node2',
    offsetX: 250,
    offsetY: 400,
    width: 100,
    height: 100,
    ports: [
      {
        id: 'port3',
        offset: { x: 0, y: 0.5 },
        visibility: PortVisibility.Visible,
      },
      {
        id: 'port4',
        offset: { x: 0.5, y: 1 },
        visibility: PortVisibility.Visible,
      },
    ],
  },
];

let connectors: ConnectorModel[]= [
  {
    id: 'connector1',
    sourceID: 'node1',
    targetID: 'node2',
    type: 'Orthogonal',
    sourcePortID: 'port1',
    targetPortID: 'port3',
    annotations: [{ content: 'connector1' }],
  },
  {
    id: 'connector2',
    sourceID: 'node2',
    targetID: 'node1',
    type: 'Orthogonal',
    sourcePortID: 'port4',
    targetPortID: 'port2',
    annotations: [{ content: 'connector2' }],
  },
];


// Method for inEdges
const inEdges = () => {
  let port1 = diagramInstance.nodes[0].ports[1];
  console.log(port1.inEdges[0]);
}

// Method for outEdges
const outEdges = () => {
  let port1 = diagramInstance.nodes[0].ports[0];
  console.log(port1.outEdges[0]);
}

// initialize Diagram component
function App() {
  return (
    <div>
      <ButtonComponent content="In Edges" onClick={inEdges} />
      <ButtonComponent content="Out Edges" onClick={outEdges} />
      <DiagramComponent
        id="container"
        ref={(diagram) => (diagramInstance = diagram)}
        width={'100%'}
        height={'600px'}
        nodes={nodes}
        connectors={connectors}
      />
    </div>
  );
}
const root = ReactDOM.createRoot(document.getElementById('diagram'));
root.render(<App />);

Additional Information to Port

The addInfo property allows attachment of custom metadata to ports. This property accepts any object and is useful for storing application-specific data, configuration settings, or contextual information that needs to be associated with particular ports. The stored information persists with the port throughout its life cycle and can be accessed when processing port-related events or operations.

The following code example shows how to attach additional information to a port:


let port:PointPortModel = {id:'port1',offset:{x:0.5,y:0},addInfo:{position:'TopCenter',id:'port1'}};

// Assign the port to a node's ports collection:
node.ports = [port];