NgDrawFlow is an Angular library for building node-based editors, workflow builders and interactive diagrams. Custom Angular components render the nodes, while the library provides the canvas, connections, selection, drag and drop, pan and zoom, validation, and reactive state synchronization.
The main package is @ng-draw-flow/core. Node positions belong to the graph model, so core works for both manually
arranged diagrams and applications that calculate positions themselves.
| Package | Purpose |
|---|---|
@ng-draw-flow/core |
Canvas, custom nodes, connectors, connections, interactions, validation and state APIs. |
@ng-draw-flow/layouts |
Optional automatic strict-tree positioning for core graphs. |
- Angular 19 or later
- Taiga UI Polymorpheus 5
- Angular forms: Reactive Forms on Angular 19+, or the Signal Forms CVA interoperability path on a compatible Angular release
npm install @ng-draw-flow/coreCreate a standalone component for a node. The node decides where its connectors are rendered and what application data is displayed. Connector ids must be unique across the complete graph; include the node id in each connector id.
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {DfInputComponent, DfOutputComponent, DrawFlowBaseNode} from '@ng-draw-flow/core';
@Component({
standalone: true,
selector: 'app-basic-node',
imports: [DfInputComponent, DfOutputComponent],
template: `
@if (!startNodeSignal()) {
<df-input
class="input"
[connectorData]="{
nodeId: nodeIdSignal(),
connectorId: nodeIdSignal() + '-input-1',
single: false,
}"
/>
}
<strong>{{ modelSignal().label }}</strong>
@if (!endNodeSignal()) {
<df-output
class="output"
[connectorData]="{
nodeId: nodeIdSignal(),
connectorId: nodeIdSignal() + '-output-1',
single: false,
}"
/>
}
`,
styles: `
:host {
position: relative;
display: block;
min-inline-size: 10rem;
}
.input,
.output {
position: absolute;
inset-block-start: 50%;
transform: translateY(-50%);
}
.input {
inset-inline-start: -1rem;
}
.output {
inset-inline-end: -1rem;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BasicNodeComponent extends DrawFlowBaseNode {}Register the node component, create a DfDataModel, and bind it through a non-nullable FormControl.
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {DfConnectionPoint, type DfDataModel, NgDrawFlowComponent, provideNgDrawFlowConfigs} from '@ng-draw-flow/core';
import {BasicNodeComponent} from './basic-node.component';
@Component({
standalone: true,
selector: 'app-editor',
imports: [NgDrawFlowComponent, ReactiveFormsModule],
template: `
<ng-draw-flow [formControl]="graph" />
`,
styles: `
ng-draw-flow {
block-size: 32rem;
}
`,
providers: [
provideNgDrawFlowConfigs({
nodes: {basic: BasicNodeComponent},
}),
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditorComponent {
readonly graph = new FormControl<DfDataModel>(
{
nodes: [
{
id: 'source',
data: {type: 'basic', label: 'Source'},
position: {x: 0, y: 0},
startNode: true,
},
{
id: 'target',
data: {type: 'basic', label: 'Target'},
position: {x: 280, y: 80},
endNode: true,
},
],
connections: [
{
source: {
nodeId: 'source',
connectorId: 'source-output-1',
connectorType: DfConnectionPoint.Output,
},
target: {
nodeId: 'target',
connectorId: 'target-input-1',
connectorType: DfConnectionPoint.Input,
},
},
],
},
{nonNullable: true},
);
}Changes made through the editor are written back to the control. Applications can also replace the complete model with
graph.setValue(nextModel). Give the editor an explicit height, as above, or place it inside a parent with a definite
height; its default height fills its container.
DfDataModel is a runtime value. Custom data and Polymorpheus labels can contain Angular components, templates or other
values that JSON cannot preserve. For persistence, save application-defined serializable data and restore runtime
content through your component or label registry when loading it.
@ng-draw-flow/core supports:
- manually positioned and draggable nodes;
- draggable connections between custom input and output connectors;
- multiple connector positions and multiple connectors per node;
- custom connector content through Polymorpheus;
- Bezier and smooth-step connection paths with configurable arrowheads;
- node and connection selection, deletion and validation;
- pan, zoom and camera controls;
- signal snapshots, RxJS event streams and imperative controls through
NgDrawFlowStoreService; - read-only or constrained editors through
provideNgDrawFlowConfigs.
Install @ng-draw-flow/layouts when a strict tree should calculate node positions automatically. It is an optional
package; core does not depend on it and continues to support fully manual graphs.
npm install @ng-draw-flow/layoutsSee the dynamic layouts documentation for tree constraints, dynamic node sizing and action-output examples.
npm ci
npm startUseful workspace commands:
npm run test
npm run lint
npm run stylelint
npm run build