Custom Nodes
When ngDiagram’s default node is not sufficient, you can create custom nodes that provide the flexibility to render any kind of content, such as shapes, icons, Angular components, images, buttons, or even more advanced structures.
This allows you to build interactive and highly customized flow elements.
You can create a custom node by extending NgDiagramNodeTemplate and implementing CustomNodeComponent.
import { Component, input } from '@angular/core';import { NgDiagramNodeSelectedDirective, type NgDiagramNodeTemplate, NgDiagramPortComponent, type Node,} from 'ng-diagram';
@Component({ imports: [NgDiagramPortComponent], // Add selection directive to automatically apply selection styles. // Note: The host element must have display: block or flex for selection box-shadow to render properly hostDirectives: [ { directive: NgDiagramNodeSelectedDirective, inputs: ['node'] }, ], template: ` <div class="custom-node"> <div class="custom-node__header">Node title</div> <div class="custom-node__content"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </div> </div> <!-- Left port for connections --> <ng-diagram-port [side]="'left'" [type]="'both'" [id]="'port-left'" /> <!-- Right port for connections --> <ng-diagram-port [side]="'right'" [type]="'both'" [id]="'port-right'" /> `, styleUrl: './node.component.scss',})export class CustomNodeComponent implements NgDiagramNodeTemplate { node = input.required<Node>();}Using the Default Node as a base
Section titled “Using the Default Node as a base”If you don’t want to start from scratch, you can use the NgDiagramBaseNodeTemplateComponent component as a way to add custom content into the default node.
Simply wrap your custom content inside the <ng-diagram-base-node-template> component.
import { Component, input } from '@angular/core';import { type NgDiagramNodeTemplate, type Node, NgDiagramBaseNodeTemplateComponent,} from 'ng-diagram';
@Component({ imports: [NgDiagramBaseNodeTemplateComponent], template: ` <ng-diagram-base-node-template [node]="node"> <input type="text" [placeholder]="'Enter text'" [attr.data-no-drag]="true" [attr.data-no-pan]="true" /> </ng-diagram-base-node-template> `,})export class CustomNodeComponent implements NgDiagramNodeTemplate { node = input.required<Node>();}Registration
Section titled “Registration”To register a custom node, you need to add it to the nodeTemplateMap.
The map associates a string key, such as myType, with a value like CustomNodeComponent, which is a reference to an Angular component class.
export class DiagramComponent { nodeTemplateMap: NgDiagramNodeTemplateMap = new Map([ ['myType', CustomNodeComponent], ]);After registering, you need to pass the map to the ng-diagram component.
<ng-diagram [model]="model" [config]="config" [nodeTemplateMap]="nodeTemplateMap" > <ng-diagram-background /> </ng-diagram>Setting Node Type
Section titled “Setting Node Type”Assigning the type property as myType for the node allows you to precisely control which template is used to render each node.
This approach makes your diagram highly extensible and flexible, as you can easily introduce new node types and associate them with different components.
model = initializeModel({ nodes: [ { id: '1', position: { x: 0, y: 0 }, size: { width: 250, height: 170 }, autoSize: false, type: 'myType', data: {}, }, ], });Custom Appearance
Section titled “Custom Appearance”Above component receives the node data as input and provides its own template and styles for rendering. In the example, the node displays a header and some content, but you can fully customize its appearance and behavior.
Node Properties
Section titled “Node Properties”By using this approach—creating custom node components that implement NgDiagramNodeTemplate and receive the node data as input—you gain full access to the Node definition and all its properties.
This means your custom node can leverage any property defined in the Node interface, such as:
interface SimpleNode<T = any> { id: string; // The unique identifier for the node. position: Point; // The position of the node in the diagram. data: T; // The data associated with the node. type?: string; // The type of the node declared in nodeTemplateMap. selected?: boolean; // Whether the node is selected. size?: Size; // The size of the node. autoSize?: boolean; // Whether the size of the node is automatically resized based on the content. zOrder?: number; // The z-order of the node. readonly computedZIndex?: number; // The z-index of the node. This value is set automatically. readonly measuredPorts?: Port[]; // The ports of the node. This value is set automatically. resizable?: boolean; // Whether the node is resizable. rotatable?: boolean; // Whether the node is rotatable. angle?: number; // The angle of the node from 0 to 360. groupId?: Node<T>['id']; // The id of the parent node.}Handling Interactive Elements
Section titled “Handling Interactive Elements”When adding interactive elements like inputs to your custom nodes, dragging on these elements might trigger unwanted diagram behaviors. You can control this using special data attributes:
data-no-pan="true"- Prevents the diagram canvas from panning when the user clicks and drags on the inputdata-no-drag="true"- Prevents the node itself from being dragged when the user clicks and drags on the input
<!-- Input that prevents both diagram panning and node dragging --><input type="text" data-no-pan="true" data-no-drag="true" placeholder="Type here" />Adding Features
Section titled “Adding Features”We also expose advanced behaviors like resizing, rotating, or customizing ports, enhancing the user experience with minimal effort.
Integrating these functionalities is straightforward simply place the corresponding components in your node’s template.
As a result, your custom nodes are not only visually flexible, but also deeply integrated with the diagram’s data model, making them powerful and adaptable for complex scenarios.