Custom Nodes, Edges & Theme Customization
Learn how to project custom Angular components into nodes, style connection handles, customize SVG edge paths, and override theme tokens.
1. Custom Node Angular Templates
You can create custom Angular components to render inside nodes. Use <ngx-workflow-handle> to declare input/output connection ports:
import { Component, input } from '@angular/core';
import { HandleComponent } from 'ngx-workflow';
@Component({
selector: 'app-custom-card-node',
standalone: true,
imports: [HandleComponent],
template: `
<div class="custom-card">
<!-- Input Connection Port -->
<ngx-workflow-handle type="target" position="left" id="input-port" />
<div class="card-header">
<span class="status-dot"></span>
<h4>Custom Card Node Title</h4>
</div>
<div class="card-body">
<p>Custom Angular signal data bindings</p>
</div>
<!-- Output Connection Port -->
<ngx-workflow-handle type="source" position="right" id="output-port" />
</div>
`
})
export class CustomCardNodeComponent {}2. Connection Limits on Ports
Cap edges per port on default or custom nodes. Number values on isConnectable also act as a max connection count.
<ngx-workflow-diagram
[nodes]="nodes()"
[edges]="edges()"
[maxConnectionsPerHandle]="2"
/>
nodes = signal<Node[]>([
{
id: 'a',
position: { x: 80, y: 100 },
ports: 4,
maxConnectionsPerPort: 1,
handleConfig: {
bottom: { maxConnections: 3 }
}
}
]);3. Direction-aware edge routing
Bezier, step, and smoothstep paths respect sourceHandle / targetHandle (top · right · bottom · left). A vertical bottom → top link curves out of the bottom port and into the top port — not a flat left-to-right diagonal.
edges = signal<Edge[]>([
{
id: 'e1',
source: 'top-node',
target: 'bottom-node',
sourceHandle: 'bottom',
targetHandle: 'top',
type: 'bezier'
}
]);4. Custom Edge Styling & Animations
Stroke, labels, and animation dots accept hex / rgb() / rgba(). Built-in markers (arrow, arrowclosed, dot) match the edge stroke color. When animated is true and animationType is omitted, flow animation is used.
edges = signal<Edge[]>([
{
id: 'e-styled',
source: 'n1',
target: 'n2',
animated: true,
animationType: 'both',
animationStyle: { fill: 'rgba(56, 189, 248, 0.9)' },
markerEnd: 'arrowclosed',
style: {
stroke: 'rgba(56, 189, 248, 0.85)',
strokeWidth: '3',
strokeDasharray: '5,5'
}
}
]);5. Node Colors (RGBA)
Set fill, text, and border via style / borderColor, or edit them in the properties sidebar RGBA pickers (swatch + opacity + rgba() text).
nodes = signal<Node[]>([
{
id: 'n1',
position: { x: 80, y: 100 },
label: 'Opaque',
style: {
backgroundColor: '#ffffff',
color: '#0f172a',
borderColor: '#94a3b8'
}
},
{
id: 'n2',
position: { x: 320, y: 100 },
label: 'Glass',
style: {
backgroundColor: 'rgba(15, 23, 42, 0.65)',
color: 'rgba(248, 250, 252, 0.95)',
borderColor: 'rgba(45, 212, 191, 0.8)'
},
borderColor: 'rgba(45, 212, 191, 0.8)'
}
]);6. CSS Theme Customization Tokens
Override default CSS variables in your application stylesheet to match your corporate design system:
:root {
/* Brand Accent Colors */
--ngx-workflow-accent: #3b82f6;
--ngx-workflow-primary: #2dd4bf;
--ngx-workflow-node-bg: #1e293b;
--ngx-workflow-node-border: #334155;
--ngx-workflow-node-text: #f8fafc;
--ngx-workflow-edge-stroke: #94a3b8;
/* Handle Ports */
--ngx-workflow-handle-color: #60a5fa;
--ngx-workflow-handle-hover: #2563eb;
/* Selected Node Border Glow */
--ngx-workflow-selected-glow: 0 0 0 2px #3b82f6;
}7. Overlay Panels & Workflow Legends
Use <ngx-workflow-panel> inside the diagram container to project floating legends, controls, or annotations. Supports 9 viewport anchor positions (top-left, top-center, top-right, center-left, center, center-right, bottom-left, bottom-center, bottom-right) and inline dynamic [style].
<ngx-workflow-diagram [nodes]="nodes" [edges]="edges">
<!-- Projected Legend Panel with 9-point positioning -->
<ngx-workflow-panel
[position]="'top-right'"
[style]="{ minWidth: '280px', background: 'rgba(15, 23, 42, 0.94)', color: '#f8fafc' }"
>
<div class="legend-card glass-panel">
<div class="legend-header">
<h4>Workflow Legend</h4>
</div>
<div class="legend-section">
<span class="legend-title">Node Status</span>
<div class="legend-item"><span class="dot bg-blue"></span> Active Ingestion</div>
<div class="legend-item"><span class="dot bg-green"></span> Database Sink</div>
<div class="legend-item"><span class="dot bg-red"></span> Alert Dead-Letter</div>
</div>
<div class="legend-section">
<span class="legend-title">Connections</span>
<div class="legend-item"><span class="line line-solid"></span> Primary Flow</div>
<div class="legend-item"><span class="line line-dashed"></span> Fallback Queue</div>
</div>
</div>
</ngx-workflow-panel>
</ngx-workflow-diagram>8. Headless Node Double-Click & REST API Inspector
Disable the default built-in properties editing sidebar ([showPropertiesSidebar]="false") and handle (nodeDoubleClick) with your custom projected API inspector panel or drawer.
<ngx-workflow-diagram
[nodes]="nodes()"
[edges]="edges()"
[showPropertiesSidebar]="false"
(nodeDoubleClick)="onNodeDoubleClick($event)"
(paneClick)="closeInspector()"
>
@if (inspectorOpen()) {
<ngx-workflow-panel [position]="'center-right'" [style]="{ zIndex: 30 }">
<div class="inspector-card glass-panel">
<h4>{{ activeNode()?.label }} REST API Schema</h4>
<p><strong>Endpoint:</strong> {{ nodeConfig()?.endpoint }}</p>
<p><strong>Throughput:</strong> {{ nodeConfig()?.throughput }}</p>
<button (click)="saveAndSync()">Save & Sync API</button>
</div>
</ngx-workflow-panel>
}
</ngx-workflow-diagram>9. Custom Zoom Controls Toolbar & Slots
Fully configure the zoom controls toolbar using [zoomControlsConfig]. Customize anchor positions (bottom-left, bottom-right, top-left, top-right), reorder buttons, or add custom action buttons and separators:
import { ZoomControlsConfig } from 'ngx-workflow';
const zoomConfig: ZoomControlsConfig = {
position: 'bottom-left',
items: [
{ id: 'zoomIn', type: 'action', action: 'zoomIn', icon: 'plus', title: 'Zoom In' },
{ id: 'zoomPercent', type: 'view', view: 'zoomPercent' },
{ id: 'zoomOut', type: 'action', action: 'zoomOut', icon: 'minus', title: 'Zoom Out' },
{ id: 'separator', type: 'separator' },
{ id: 'fitView', type: 'action', action: 'fitView', icon: 'fit', title: 'Fit View' },
{ id: 'fullscreen', type: 'action', action: 'fullscreen', icon: 'fullscreen', title: 'Fullscreen' },
]
};
// In template:
// <ngx-workflow-diagram [nodes]="nodes" [edges]="edges" [zoomControlsConfig]="zoomConfig" />