ngx-workflow

npm version License

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.

Live demo & docs: ngx-workflow.vercel.app ยท local: npm start then Examples or Canvas Studio (/sandbox).

AI / LLM index: llms.txt ยท llms-full.txt

๐Ÿš€ Features

Core Features

  • Native Angular: Built from the ground up for Angular, using Signals and OnPush change detection
  • Interactive: Drag & drop nodes, zoom & pan canvas, connect edges
  • Node Palette: Drag-and-drop stencil panel (<ngx-workflow-palette>) to drop new nodes directly onto canvas
  • Typed Ports: Port data type validation (dataType) to prevent connecting incompatible handle types
  • Manual Edge Waypoints: Custom bendpoint support (waypoints?: Array<{ x: number, y: number }>) for manual routing
  • Reactive Forms Integration: Full ControlValueAccessor (formControlName / [(ngModel)]) support with built-in graph validators (noCycles, noOrphanNodes, minNodes)
  • Customizable: Fully custom node and edge templates
  • Rich UI: Built-in minimap, background patterns, controls, alignment, and equal distribution tools
  • Parallel Edge Offsetting: Automatic curvature spacing for multi-edges between identical node pairs
  • Layouts: Automatic layout support via ELK (plus force, hierarchical, and circular helpers)
  • History: Robust Undo/Redo history stack with Ctrl+Z/Ctrl+Shift+Z
  • Theming: Explicit colorMode and CSS variables for easy styling with dark mode support
  • Smart Alignment: Visual alignment guides and drag snapping

Advanced Features

  • Snap-to-Grid: Configurable grid snapping for precise node placement
  • Space Panning: Professional canvas panning with Space + Drag
  • Export Controls: Built-in UI for PNG, SVG, and clipboard export
  • Clipboard Operations: Full copy/paste/cut support with Ctrl+C/V/X and localStorage persistence
  • Connection Validation: Prevent invalid connections with custom validators
  • Collision Detection: Optional collision prevention to stop nodes from overlapping
  • Edge Reconnection: Drag edge endpoints to reconnect them

Visuals & Motion

  • Edge Animation: Flow dash and/or moving-dot particles (animated, animationType: 'flow' | 'dot' | 'both')
  • RGBA Colors: Node fill/text/border and edge stroke/label/animation colors support hex, rgb(), and rgba()
  • Node Motion: Programmatic API to animate nodes along edge paths
  • Markers: Built-in arrow, arrowclosed, dot tinted to match the edge stroke; custom SVG via [defsTemplate]
  • Background Images: Support for custom background images via [backgroundImage]

Built-in UI Components

  • Search Bar: Press Ctrl+F to search nodes by label/id.
  • Properties Panel: Sidebar for node/edge editing (RGBA pickers, animation, markers); auto-shows on selection.
  • Context Menu: Right-click canvas/nodes/edges for actions.
  • Layout Alignment: Auto-align selected nodes (if showLayoutControls is true).
  • Minimap: Navigable overview of complex flows.

Content Projection (Slots)

  • Node Toolbars: Show contextual buttons above selected nodes (<ngx-workflow-node-toolbar>).
  • Overlay Panels: Add anchored overlays to the canvas with 9-point positioning and inline dynamic styling (<ngx-workflow-panel>).
Example :
<ngx-workflow-diagram [nodes]="nodes()" [edges]="edges()" [showPropertiesSidebar]="false" (nodeDoubleClick)="onNodeDoubleClick($event)">
  <!-- Shows above selected node -->
  <ngx-workflow-node-toolbar [nodeId]="selectedNodeId">
    <button (click)="deleteNode()">Delete</button>
  </ngx-workflow-node-toolbar>

  <!-- Anchored Workflow Legend Panel -->
  <ngx-workflow-panel position="top-right" [style]="{ minWidth: '280px', background: 'rgba(15, 23, 42, 0.94)', color: '#f8fafc' }">
    <div class="legend-card">
      <h4>Workflow Legend</h4>
      <div class="legend-item"><span class="dot bg-blue"></span> Active / Ingestion</div>
      <div class="legend-item"><span class="dot bg-emerald"></span> Database Sink</div>
    </div>
  </ngx-workflow-panel>

  <!-- Custom Node Double-Click API Inspector -->
  @if (inspectorOpen()) {
    <ngx-workflow-panel position="center-right" [style]="{ zIndex: 30 }">
      <div class="inspector-card glass-panel">
        <h4>{{ activeNode()?.label }} API Config</h4>
        <input [(ngModel)]="activeEndpoint" placeholder="API endpoint" />
        <button (click)="syncApi()">Save & Sync API</button>
      </div>
    </ngx-workflow-panel>
  }
</ngx-workflow-diagram>

๐Ÿ“ฆ Installation

Example :
npm install ngx-workflow

Peer dependencies: @angular/core, @angular/common, and @angular/forms (Angular 17.1 through 22).

๐Ÿ Quick Start

Import NgxWorkflowModule directly into your standalone component's imports array.

Example :
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
        [nodes]="nodes"
        [edges]="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', animated: true }
  ];

  onNodeClick(node: Node) {
    console.log('Clicked:', node);
  }

  onConnect(connection: any) {
    console.log('Connected:', connection);
  }
}

๐Ÿ“– API Reference

<ngx-workflow-diagram>

The main component for rendering the workflow.

Inputs

NameTypeDefaultDescription
nodesNode[][]Array of nodes to display (Signal-based sync).
edgesEdge[][]Array of edges to display.
initialViewportViewportundefinedInitial viewport state { x, y, zoom }.
showZoomControlsbooleantrueWhether to show the zoom control buttons (bottom-left).
zoomControlsConfigZoomControlsConfigundefinedCustom slots, positions (bottom-left, top-right, etc.), actions, and icons for zoom controls.
minZoomnumber0.1Minimum zoom level.
maxZoomnumber4Maximum zoom level.
showMinimapbooleantrueWhether to show the minimap (bottom-right).
showBackgroundbooleantrueWhether to show the background pattern.
backgroundVariant'dots' | 'lines' | 'cross''dots'The pattern style of the background.
backgroundImagestring | nullnullURL for a custom background image.
backgroundGapnumber20Gap between background pattern elements.
backgroundSizenumber1Size of background pattern elements.
backgroundColorstring'#81818a'Color of the background pattern dots/lines.
backgroundBgColorstring'#f0f0f0'Background color of the canvas itself.
connectionValidator(source: string, target: string) => booleanundefinedCustom function to validate connections globally.
validateConnection(connection) => booleanundefinedRicher connection validation including handle ids.
nodesResizablebooleantrueGlobal toggle to enable/disable node resizing.
snapToGridbooleanfalseEnable snap-to-grid for node positioning.
gridSizenumber20Grid size in pixels for snap-to-grid.
showExportControlsbooleanfalseShow export controls UI (PNG, SVG, Clipboard).
showUndoRedoControlsbooleantrueShow history controls UI.
showLayoutControlsbooleanfalseShow auto-layout controls.
showSearchControlsbooleantrueShow floating Ctrl+F search controls.
showPropertiesSidebarbooleanfalseEnable/disable built-in node/edge properties sidebar on double-click.
colorMode'light' | 'dark''light'Color theme mode.
zIndexMode'default' | 'layered''default'Strategy for node z-indexing.
preventNodeOverlapbooleanfalseEnable collision detection to prevent partial overlaps.
nodeSpacingnumber10Minimum spacing between nodes when preventNodeOverlap is true.
edgeReconnectablebooleanfalseAllow dragging edge endpoints to reconnect them.
optimizationFlowOptimization{ ... }Performance tuning (spatial index culling, hideEdgesBelowZoom, adaptive buffer).
autoSavebooleanfalseEnable auto-saving of diagram state to localStorage.
autoSaveIntervalnumber1000throttled auto-save interval in ms.
autoPanOnNodeDragbooleantruePan canvas automatically when dragging node near edge.
autoPanOnConnectbooleantruePan canvas automatically when connecting edges near boundary.
autoPanSpeednumber15Pixels per frame for auto-pan.
autoPanEdgeThresholdnumber50Distance in pixels from edge to trigger auto-pan.
defsTemplateTemplateRef<any>undefinedAngular template containing SVG <defs> (markers, etc).
edgeTemplateTemplateRef<any>undefinedCustom template for rendering edges.
maxConnectionsPerHandlenumberundefinedGlobal max edges per port. Overridden by node.maxConnectionsPerPort and handleConfig[port].maxConnections.
proximityThresholdnumber200Distance for auto-connect when dragging nodes near each other.
showGridbooleanfalseShow grid overlay.
nodeTypesRecord<string, Type>{}Custom node type โ†’ component map.
initialNodes / initialEdgesNode[] / Edge[][]Seed graph on first init (uncontrolled).
maxVersionsnumber10Max auto-save version snapshots.

Connection limits example

Example :
<ngx-workflow-diagram
  [nodes]="nodes()"
  [edges]="edges()"
  [maxConnectionsPerHandle]="2"
  (nodesChange)="nodes.set($event)"
  (edgesChange)="edges.set($event)"
  (connect)="onConnect($event)"
/>

nodes.set([{
  id: 'a',
  position: { x: 0, y: 0 },
  ports: 4,
  maxConnectionsPerPort: 1,
  handleConfig: { bottom: { maxConnections: 3 } }
}]);

Priority: handleConfig[port].maxConnections โ†’ maxConnectionsPerPort โ†’ [maxConnectionsPerHandle]. Also editable in the properties sidebar.

Methods

You can access these methods via @ViewChild(DiagramComponent):

MethodReturnDescription
fitView(options?)voidFits all nodes in viewport. Options: { zoom?: number, align?: 'center' | 'top-center', paddingTop?: number }.
zoomIn()voidIncreases zoom level by 20%.
zoomOut()voidDecreases zoom level by 20%.
resetZoom()voidResets zoom to 100%.
exportToPNG(filename, options)voidExport canvas as PNG.
exportToSVG(filename, options)voidExport canvas as SVG.
copyToClipboard(options)voidCopy diagram image to clipboard.

Outputs

NameTypeDescription
nodeClickoutput<Node>Emitted when a node is clicked.
nodeDoubleClickoutput<Node>Emitted when a node is double-clicked.
edgeClickoutput<Edge>Emitted when an edge is clicked.
edgeDoubleClickoutput<Edge>Emitted when an edge is double-clicked.
connectoutput<{source, target, sourceHandle?, targetHandle?}>New port-to-port connection created.
connectStart / connectEndoutput<{nodeId, handleId?}>Connection drag lifecycle.
edgeDropoutput<{sourceNodeId, sourceHandleId, position}>Connection dropped on empty canvas.
connectionDropoutput<{position, event, sourceNodeId, sourceHandleId?}>Connection drop with pointer details.
nodesChangeoutput<Node[]>Nodes moved, added, deleted, or edited.
edgesChangeoutput<Edge[]>Edges added, reconnected, or deleted.
paneClickoutput<{event, position}>Empty canvas click (graph-space position).
paneScrolloutput<WheelEvent>Wheel scroll on the canvas.
contextMenuoutput<{type, item?, event}>Right-click on canvas / node / edge.
beforeDeleteoutput<{nodes, edges, cancel}>Cancellable delete.
importErroroutput<{message, error?}>JSON import failure.
nodeMouseEnter / nodeMouseLeaveoutput<Node>Pointer enter/leave node.
nodeMouseMoveoutput<{node, event}>Pointer move over a node.
edgeMouseEnter / edgeMouseLeaveoutput<Edge>Pointer enter/leave edge.
zoomControlsActionClickoutput<{id, action, event}>Custom or built-in action button clicked in the zoom controls toolbar.
fullscreenoutput<void>Canvas fullscreen toggled via toolbar.
undo / redooutput<void>Undo or redo triggered via toolbar.
zoomIn / zoomOut / resetZoomoutput<void>Zoom changes triggered via toolbar.

<ngx-workflow-panel>

An anchored overlay container projected inside <ngx-workflow-diagram> for building floating legends, control panels, stats HUDs, or inspection cards.

Inputs

NameTypeDefaultDescription
positionPanelPosition'top-left'9 anchor presets: 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'.
classNamestringundefinedCustom CSS class applied to the panel container.
stylestring | Record<string, string | number>undefinedDynamic inline styles (e.g. minWidth, background, boxShadow, zIndex).

<ngx-workflow-node-toolbar>

A floating contextual action toolbar that anchors directly above/below an active node.

Inputs

NameTypeDefaultDescription
nodeIdstringrequiredID of the node to attach this floating toolbar to.
position'top' | 'bottom' | 'left' | 'right''top'Side of the node where the toolbar floats.
offsetnumber10Offset distance in pixels from the node boundary.

Interfaces

Node

Example :
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)
  zIndex?: number;         // Manual Z-Index
  class?: string;          // Custom CSS class
  // Styling โ€” colors accept hex / rgb() / rgba()
  style?: {
    backgroundColor?: string;
    color?: string;
    borderColor?: string;
    [key: string]: any;
  };
  shadow?: boolean | string;   // Drop shadow
  borderStyle?: 'solid' | 'dashed' | 'dotted' | 'none';
  borderColor?: string;
  borderWidth?: number;

  // Behavior
  ports?: 0 | 1 | 2 | 3 | 4; // 0=None, 1=Top, 2=Top/Bottom, 3=Left/Right, 4=All
  maxConnectionsPerPort?: number; // Default max edges per port on this node
  handleConfig?: {
    [handleId: string]: {
      isConnectable?: boolean | number | ((node: Node, edges: Edge[]) => boolean);
      maxConnections?: number; // Override for this port
    };
  };
  easyConnect?: boolean;   // Drag from node body to connect
  
  // Visuals
  badges?: Array<{
    content: string;
    color?: string;
    backgroundColor?: string;
    position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
  }>;
}

Edge

Example :
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' | 'smoothstep' | 'smart' | 'dashed';
  animated?: boolean;      // Defaults animationType to 'flow' when unset
  animationType?: 'flow' | 'dot' | 'both';
  animationDuration?: string; // e.g. '1s'
  animationStyle?: { fill?: string };
  markerStart?: 'arrow' | 'arrowclosed' | 'dot' | string;
  markerEnd?: 'arrow' | 'arrowclosed' | 'dot' | string; // Built-ins match stroke
  style?: { stroke?: string; strokeWidth?: string | number; strokeDasharray?: string; [key: string]: any };
  labelStyle?: { fill?: string; [key: string]: any };
}

Standalone properties sidebar: bind (nodeChange) / (edgeChange) (not (change) for nodes).

<ngx-workflow-zoom-controls> & [zoomControlsConfig]

Configure the floating zoom and workflow toolbar on <ngx-workflow-diagram> or mount standalone:

Example :
<ngx-workflow-diagram
  [nodes]="nodes()"
  [edges]="edges()"
  [zoomControlsConfig]="{
    position: 'bottom-left',
    orientation: 'horizontal',
    items: [
      { id: 'undo', type: 'action', action: 'undo' },
      { id: 'redo', type: 'action', action: 'redo' },
      { id: 'sep1', type: 'separator' },
      { id: 'zoomIn', type: 'action', action: 'zoomIn', icon: 'plus' },
      { id: 'zoomPercent', type: 'view', view: 'zoomPercent' },
      { id: 'zoomOut', type: 'action', action: 'zoomOut', icon: 'minus' },
      { id: 'sep2', type: 'separator' },
      { id: 'fitView', type: 'action', action: 'fitView', icon: 'fit' },
      { id: 'fullscreen', type: 'action', action: 'fullscreen', icon: 'fullscreen' }
    ]
  }"
  (fullscreen)="toggleFullscreen()"
/>
Config PropertyTypeDefaultDescription
positionZoomControlsPosition'bottom-left'8 anchor presets: 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'.
orientation'horizontal' | 'vertical''horizontal'Layout direction of toolbar buttons and dividers.
stylestring | Record<string, string | number>undefinedCustom inline CSS styles for toolbar container.
classNamestringundefinedCustom CSS class applied to container.
itemsZoomControlItem[][...]Full array controlling slot order, built-in/custom actions, views, labels, custom SVGs, and separators.

Handle (Component)

Use <ngx-workflow-handle> inside your custom nodes.

Example :
<ngx-workflow-handle
    type="source"
    position="right"
    [isConnectable]="true"
    [isValidConnection]="validateConnectionFn"
></ngx-workflow-handle>
InputTypeDescription
type'source' | 'target'Type of handle.
position'top' | 'right' | 'bottom' | 'left'Position on the node boundary.
isValidConnection(connection) => booleanFunction to validate connections for this specific handle.

Custom Edges

Similar to nodes, you can register custom edge components via the edge types token. Built-in path types include bezier, straight, step, smoothstep, and smart.

  1. Create Edge Component: A standalone component that accepts an edge input (EdgeComponentType).
  2. Register Token:Example :
    import { NGX_WORKFLOW_EDGE_TYPES } from 'ngx-workflow';
    providers: [
      { provide: NGX_WORKFLOW_EDGE_TYPES, useValue: { 'my-edge': CustomEdgeComponent } }
    ]

๐ŸŽจ Custom Customization

Edge Markers

Built-in markers (arrow, arrowclosed, dot) match edge.style.stroke (including rgba). For custom SVG markers, pass a template to [defsTemplate]:

Example :
<ng-template #defs>
  <svg:marker id="my-marker" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="5" markerHeight="5">
    <circle cx="5" cy="5" r="5" fill="red" />
  </svg:marker>
</ng-template>

<ngx-workflow-diagram [defsTemplate]="defs" ...></ngx-workflow-diagram>

Then use it in your edge: { id: 'e1', ..., markerEnd: 'my-marker' }.

Styling

ngx-workflow uses CSS variables for easy theming. Override these in your global styles:

Example :
: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;
}

Mobile & Touch Support

  • Pinch-to-Zoom: Two-finger pinch gesture scales the diagram centered at the focal midpoint.
  • Two-Finger Pan: Dragging with two fingers smoothly pans the canvas.
  • Touch Action Guard: Blocks default browser scrolling and gestures automatically.

Accessibility (a11y)

  • Full ARIA markup (role="application", role="graphics-document", role="button", role="img", tabindex="0", and aria-label).
  • Full screen reader navigation for nodes, edges, minimap, and zoom controls.

โŒจ๏ธ Keyboard Shortcuts

Navigation & Focus Traversal

ShortcutAction
Tab / Shift + TabCycle keyboard focus through nodes
Arrow KeysFollow connected edges to focus upstream/downstream nodes
Shift + Arrow KeysNudge selected node(s) by grid steps (10px / gridSize)
Space + DragPan canvas
Shift + DragLasso selection
Ctrl + ClickMulti-select
Mouse WheelZoom in/out
Enter / SpaceSelect/toggle focused node
EscapeClear selection and node focus

Editing

ShortcutAction
Delete / BackspaceDelete selected nodes/edges
Ctrl + ZUndo
Ctrl + Shift + Z / Ctrl + YRedo

Clipboard Operations

ShortcutAction
Ctrl + CCopy selected nodes
Ctrl + VPaste copied nodes
Ctrl + XCut selected nodes
Ctrl + DDuplicate selected nodes

Export

ShortcutAction
Ctrl + Shift + EExport as PNG
Ctrl + Shift + SExport as SVG
Ctrl + Shift + CCopy to clipboard

Grouping

ShortcutAction
Ctrl + GGroup selected nodes
Ctrl + Shift + GUngroup selected group

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide for details.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


See ADVANCED_FEATURES.md for details on Space Panning, Exports, Grid Snapping, and more.

results matching ""

    No results matching ""