A powerful, highly customizable Angular library for building interactive node-based editors, flow charts, and diagrams. Built with Angular Signals for high performance and reactivity.
- Native Angular: Built from the ground up for Angular, using Signals and OnPush change detection.
- Interactive: Drag & drop nodes, zoom & pan canvas, connect edges.
- Customizable: Fully custom node and edge templates.
- Rich UI: Built-in minimap, background patterns, controls, and alignment tools.
- Layouts: Automatic layout support via Dagre and ELK.
- History: Robust Undo/Redo history stack.
- Export: Export to JSON, PNG, or SVG.
- Theming: Extensive CSS variables for easy styling.
npm install ngx-workflowYou can use ngx-workflow in two ways: Standalone Component (recommended for Angular 14+) or NgModule.
Import NgxWorkflowModule directly into your standalone component's imports array.
import { Component } from '@angular/core';
import { NgxWorkflowModule, Node, Edge } from 'ngx-workflow';
@Component({
selector: 'app-root',
standalone: true,
imports: [NgxWorkflowModule],
template: `
<div style="height: 100vh; width: 100%;">
<ngx-workflow-diagram
[initialNodes]="nodes"
[initialEdges]="edges"
(nodeClick)="onNodeClick($event)"
(connect)="onConnect($event)"
></ngx-workflow-diagram>
</div>
`
})
export class AppComponent {
nodes: Node[] = [
{ id: '1', position: { x: 100, y: 100 }, label: 'Start', type: 'default' },
{ id: '2', position: { x: 300, y: 100 }, label: 'End', type: 'default' }
];
edges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', sourceHandle: 'right', targetHandle: 'left' }
];
onNodeClick(node: Node) {
console.log('Clicked:', node);
}
onConnect(connection: any) {
console.log('Connected:', connection);
}
}If you are using NgModules, import NgxWorkflowModule in your module.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgxWorkflowModule } from 'ngx-workflow';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
NgxWorkflowModule // Import the module here
],
bootstrap: [AppComponent]
})
export class AppModule { }Then use it in your component template just like in the standalone example.
The main component for rendering the workflow.
| Name | Type | Default | Description |
|---|---|---|---|
initialNodes |
Node[] |
[] |
Initial array of nodes to display. |
initialEdges |
Edge[] |
[] |
Initial array of edges to display. |
initialViewport |
Viewport |
undefined |
Initial viewport state { x, y, zoom }. |
showZoomControls |
boolean |
true |
Whether to show the zoom control buttons (bottom-left). |
showMinimap |
boolean |
true |
Whether to show the minimap (bottom-right). |
showBackground |
boolean |
true |
Whether to show the background pattern. |
backgroundVariant |
'dots' | 'lines' | 'cross' |
'dots' |
The pattern style of the background. |
backgroundGap |
number |
20 |
Gap between background pattern elements. |
backgroundSize |
number |
1 |
Size of background pattern elements. |
backgroundColor |
string |
'#81818a' |
Color of the background pattern dots/lines. |
backgroundBgColor |
string |
'#f0f0f0' |
Background color of the canvas itself. |
connectionValidator |
(source: string, target: string) => boolean |
undefined |
Custom function to validate connections. Return false to prevent connection. |
nodesResizable |
boolean |
true |
Global toggle to enable/disable node resizing. |
| Name | Type | Description |
|---|---|---|
nodeClick |
EventEmitter<Node> |
Emitted when a node is clicked. |
edgeClick |
EventEmitter<Edge> |
Emitted when an edge is clicked. |
connect |
EventEmitter<Connection> |
Emitted when a new connection is created. |
nodesChange |
EventEmitter<Node[]> |
Emitted when the nodes array changes (move, add, delete). |
edgesChange |
EventEmitter<Edge[]> |
Emitted when the edges array changes. |
nodeDoubleClick |
EventEmitter<Node> |
Emitted when a node is double-clicked. |
interface Node {
id: string; // Unique identifier
position: { x: number; y: number }; // Position on canvas
label?: string; // Default label
data?: any; // Custom data passed to your custom node component
type?: string; // 'default', 'group', or your custom type
width?: number; // Width in pixels (default: 170)
height?: number; // Height in pixels (default: 60)
draggable?: boolean; // Is the node draggable? (default: true)
selectable?: boolean; // Is the node selectable? (default: true)
connectable?: boolean; // Can edges be connected? (default: true)
resizable?: boolean; // Is this specific node resizable? (default: true)
class?: string; // Custom CSS class
style?: object; // Custom inline styles
}interface Edge {
id: string;
source: string; // ID of source node
target: string; // ID of target node
sourceHandle?: string; // ID of source handle (optional)
targetHandle?: string; // ID of target handle (optional)
label?: string; // Label text displayed on the edge
type?: 'bezier' | 'straight' | 'step'; // Path type (default: 'bezier')
animated?: boolean; // Show animation (dashed moving line)?
markerEnd?: 'arrow' | 'arrowclosed'; // Arrowhead type
style?: object; // SVG styles (stroke, stroke-width, etc.)
}You can create your own node types by creating an Angular component and registering it.
-
Create the Component: It should accept an input
node.@Component({ selector: 'app-custom-node', template: ` <div class="custom-node"> <div class="header">{{ node.data.title }}</div> <div class="content">{{ node.data.content }}</div> <!-- Add handles --> <ngx-workflow-handle type="source" position="right"></ngx-workflow-handle> <ngx-workflow-handle type="target" position="left"></ngx-workflow-handle> </div> `, styles: [` .custom-node { border: 1px solid #333; background: white; border-radius: 4px; } .header { background: #eee; padding: 4px; border-bottom: 1px solid #333; } .content { padding: 8px; } `] }) export class CustomNodeComponent { @Input() node!: Node; }
-
Register the Component: Provide it in your module configuration using
NGX_WORKFLOW_NODE_TYPES.import { NGX_WORKFLOW_NODE_TYPES } from 'ngx-workflow'; providers: [ { provide: NGX_WORKFLOW_NODE_TYPES, useValue: { 'my-custom-type': CustomNodeComponent } } ]
-
Use it:
{ id: '3', type: 'my-custom-type', position: { x: 0, y: 0 }, data: { title: 'My Node', content: '...' } }
ngx-workflow uses CSS variables for easy theming. Override these in your global styles:
:root {
--ngx-workflow-primary: #3b82f6;
--ngx-workflow-bg: #f8fafc;
--ngx-workflow-grid-color: #e2e8f0;
--ngx-workflow-node-bg: #ffffff;
--ngx-workflow-node-border: #cbd5e1;
--ngx-workflow-handle-color: #3b82f6;
--ngx-workflow-edge-stroke: #64748b;
--ngx-workflow-selection-stroke: #3b82f6;
}| Shortcut | Action |
|---|---|
Delete / Backspace |
Delete selected nodes/edges |
Ctrl + Z |
Undo |
Ctrl + Shift + Z |
Redo |
Shift + Drag |
Lasso Selection |
Ctrl + Click |
Multi-select |
Ctrl + C |
Copy |
Ctrl + V |
Paste |
Ctrl + X |
Cut |
Ctrl + D |
Duplicate |
Ctrl + G |
Group Selected Nodes |
Ctrl + Shift + G |
Ungroup Selected Group |
Contributions are welcome! Please read our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.
