@flowchart-sequence-designer/angular

May 19, 2026 ยท View on GitHub

npm CI CodeQL

Angular wrapper for flowchart-sequence-designer โ€” embed the full-featured flowchart & sequence-diagram editor in Angular apps using standalone components.

๐Ÿ”— Live demo & developer docs โ†’ Open it to drive the editor, switch variants (Flowchart / Question / Journey / Sequence), and explore the docs tab for API snippets. Every variant boots with a working sample diagram so you can poke without any setup.

Installation

npm install @flowchart-sequence-designer/angular flowchart-sequence-designer react react-dom

Angular 16+ is required (standalone components). The core API has zero runtime dependencies; React 18+ is a peer dependency for the visual editor.

Components

ComponentSelectorDescription
FsdDiagramComponent<fsd-diagram>Full diagram editor (flowchart/question/journey)
FsdSequenceComponent<fsd-sequence>Sequence diagram editor
FsdToolbarComponent<fsd-toolbar>Standalone export/import toolbar
FsdStepEditorComponent<fsd-step-editor>Node property editor panel

All components are standalone โ€” import them directly, no NgModule required.

Quick Start

Flowchart Editor

import { Component } from '@angular/core';
import { FsdDiagramComponent } from '@flowchart-sequence-designer/angular';
import type { DiagramModel } from '@flowchart-sequence-designer/angular';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [FsdDiagramComponent],
  template: `
    <fsd-diagram
      [height]="600"
      [theme]="'dark'"
      [allowImport]="true"
      (modelChange)="onModelChange($event)"
      (exportEvent)="onExport($event)"
    />
  `,
})
export class AppComponent {
  onModelChange(model: DiagramModel) {
    console.log('Model updated:', model);
  }

  onExport(event: { format: string; content: string | Blob }) {
    console.log('Exported:', event.format);
  }
}

That's it โ€” no provider, no theme setup, no required inputs. The editor mounts with a sample diagram, a working toolbar, undo/redo, drag-to-pan, scroll-to-zoom, and export buttons for Mermaid / PlantUML / JSON / SVG / PNG. Pass [theme]="'dark'" or [themeOverrides]="brandColors" to brand-match, or [initialModel]="emptyModel('flowchart')" to start blank.

Sequence Diagram Editor

import { Component } from '@angular/core';
import { FsdSequenceComponent, presetSequenceModel } from '@flowchart-sequence-designer/angular';

@Component({
  selector: 'app-sequence',
  standalone: true,
  imports: [FsdSequenceComponent],
  template: `
    <fsd-sequence
      [initialModel]="model"
      [height]="500"
      [theme]="'auto'"
      (modelChange)="onModelChange($event)"
    />
  `,
})
export class SequencePageComponent {
  model = presetSequenceModel();
  onModelChange(model: any) { /* ... */ }
}

Using with an Initial Model

import { presetFlowchartModel, emptyModel } from '@flowchart-sequence-designer/angular';

// Pre-built flowchart with sample nodes
const flowchart = presetFlowchartModel('flowchart');

// Empty model of any type
const blank = emptyModel('flowchart', 'question');

Programmatic API

The core library (flowchart-sequence-designer) exposes a fluent builder API, import/export functions, and a low-level Model class. These are re-exported from @flowchart-sequence-designer/angular for convenience.

Flowchart builder

import { flowchart } from 'flowchart-sequence-designer';

const diagram = flowchart('Order Flow')
  .node('start',   'Start',           { shape: 'circle' })
  .node('check',   'Payment valid?',  { shape: 'diamond' })
  .node('success', 'Confirm order',   { shape: 'rectangle' })
  .node('fail',    'Reject',          { shape: 'rectangle' })
  .edge('start',   'check')
  .edge('check',   'success', { label: 'Yes' })
  .edge('check',   'fail',    { label: 'No' });

console.log(diagram.toMermaid());

Node shapes

ShapeDescription
rectangleStandard process box (default)
diamondDecision / branch
circleStart or end terminal
parallelogramInput / output

Edge options

.edge(from, to, {
  label?: string,
  style?: 'solid' | 'dashed' | 'dotted',
  arrowhead?: 'arrow' | 'open' | 'none',
})

Sequence diagram builder

import { sequence } from 'flowchart-sequence-designer';

const diagram = sequence('Auth Flow')
  .actor('User')
  .actor('Server')
  .message('User',   'Server', 'POST /login')
  .message('Server', 'User',   '200 OK + token', { style: 'dashed' });

console.log(diagram.toMermaid());

Actors auto-register from message() calls, so you can skip .actor() if you prefer.


Export formats

Every builder exposes the same export methods:

diagram.toMermaid()   // string
diagram.toPlantUML()  // string
diagram.toJSON()      // string (serialised DiagramModel)
diagram.toSVG()       // string (SVG markup)
diagram.toPNG()       // Promise<Blob>  (browser only)

Import

import { fromMermaid, fromJSON } from 'flowchart-sequence-designer';

const model = fromMermaid('graph TD; A-->B; B-->C');
const model2 = fromJSON(jsonString);

Round-trip fidelity: fromMermaid(diagram.toMermaid()) produces an equivalent model.

You can also feed imported models directly into the Angular component:

import { Component } from '@angular/core';
import { FsdDiagramComponent } from '@flowchart-sequence-designer/angular';
import { fromMermaid } from 'flowchart-sequence-designer';

@Component({
  standalone: true,
  imports: [FsdDiagramComponent],
  template: `<fsd-diagram [initialModel]="model" />`,
})
export class ImportedComponent {
  model = fromMermaid('graph TD; A-->B; B-->C');
}

Exporter / importer round-trip rules

The five export formats trade fidelity for portability:

FormatRound-tripPreservedDropped or lossy
JSONโœ… fullevery field โ€” variant, metadata, waypoint, x/y positions, edge arrowheads, message ordernothing
Mermaid (flowchart)partialnode shapes ([] {} (()) [/]), labels, edge connectors (-->, -.->, ---, -.-), edge labels, subgraph โ†’ metadata.grouppositions, waypoint, metadata.answers, variant. Dotted edges collapse to dashed.
Mermaid (sequence)partialactor order, message arrows (->>, -->>), labelsmessage metadata, styling overrides
PlantUML (flowchart)export-onlyedge styles (--> / -[dashed]-> / -[dotted]->), labels, node idshape distinctions (PlantUML state-diagram syntax is coarser), positions, metadata, variant
PlantUML (sequence)export-onlyactor order, message style (->, -->), labelsโ€“
SVGexport-only (rendered)full visual parity with the canvas โ€” same dot grid, same edge curves, same node stylingโ€“
PNGexport-only (rendered, browser-only)same as SVG, rasterized at devicePixelRatioโ€“

If you need 100% round-trip fidelity, use JSON. If you need a format that GitHub renders inline in markdown, use Mermaid. If you need a polished image for documentation, use SVG or PNG.


Presets & empty models

import {
  presetFlowchartModel,
  presetSequenceModel,
  emptyModel,
} from '@flowchart-sequence-designer/angular';

presetFlowchartModel('flowchart')  // 6-node order flow with one decision
presetFlowchartModel('question')   // 1-question / 3-answer router
presetFlowchartModel('journey')    // 5-step onboarding sequence
presetSequenceModel()              // 3-actor login handshake

emptyModel('flowchart')            // { type:'flowchart', variant:'flowchart', nodes:[], edges:[] }
emptyModel('flowchart', 'journey') // same with variant: 'journey'
emptyModel('sequence')             // { type:'sequence', nodes:[], edges:[], actors:[], messages:[] }

All presets return a deep clone โ€” mutate the result freely.


Working with the model directly

import { Model } from 'flowchart-sequence-designer';

const m = new Model('flowchart');
m.addNode({ id: 'a', label: 'Step A', shape: 'rectangle' });
m.addNode({ id: 'b', label: 'Step B', shape: 'rectangle' });
m.addEdge({ id: 'e1', from: 'a', to: 'b', label: 'next' });

console.log(m.toMermaid());

API Reference

<fsd-diagram> โ€” FsdDiagramComponent

InputTypeDefaultDescription
initialModelDiagramModelpresetPre-populate the editor
heightstring | number'500px'Container height
allowedExportsExportFormat[]allRestrict export menu
allowImportbooleanfalseShow import button
variant'flowchart' | 'question' | 'journey''flowchart'Editor variant
theme'light' | 'dark' | 'auto''light'Color theme
themeOverridesPartial<ThemeColors>โ€”Custom colors
OutputPayloadDescription
modelChangeDiagramModelEmitted on every edit
exportEvent{ format, content }Emitted when user exports

Note: Changing initialModel after first render will re-mount the entire editor (full reset).

<fsd-sequence> โ€” FsdSequenceComponent

Same as <fsd-diagram> except no variant input. Accepts Partial<SequenceThemeColors> for themeOverrides.

<fsd-toolbar> โ€” FsdToolbarComponent

InputTypeDescription
allowedExportsExportFormat[]Which formats to show
allowImportbooleanShow import button
OutputPayloadDescription
exportRequestExportFormatFormat the user chose
importRequeststringRaw text the user imported

<fsd-step-editor> โ€” FsdStepEditorComponent

InputTypeRequiredDescription
nodeIdstringโœ“ID of the node to edit
modelDiagramModelโœ“Current diagram model
variantDiagramVariantEditor variant
isDarkbooleanDark mode flag
themeColorsThemeColorsTheme color overrides
OutputPayloadDescription
modelChangeDiagramModelUpdated model after edit

Diagram variants

VariantDescription
flowchartGeneral purpose โ€” any shapes, freeform connections
questionEach node is a question with lettered answer options (A, B, Cโ€ฆ). Each answer has its own connection port.
journeyNumbered milestone steps โ€” user path or process walkthrough

Editor features

Canvas

  • Drag nodes to reposition (snaps to 24px grid)
  • Scroll to zoom in/out (pinch to zoom on touch)
  • Drag the canvas background to pan (one-finger pan on touch)
  • Double-click a node to rename it inline
  • Dashed alignment guides appear when a dragged node lines up with a sibling's edge or center, and it snaps within 4 px
  • Bottom-right minimap โ€” click or drag to pan the viewport
  • Accessibility: every node, port, and control is keyboard-reachable with a visible focus ring; selection / add / delete actions announce via an aria-live status region; the edge-flow animation honours prefers-reduced-motion

Connecting nodes

  • Hover a node to reveal the bottom port dot, then drag it to another node
  • Question variant: each answer row has its own port dot โ€” drag it to route that answer to a specific node

Node Navigator (left panel)

  • Lists all nodes with shape badge, label, and connection counts
  • Search/filter by name
  • Click any row to jump to that node and center the canvas on it
  • Collapses to a slim icon strip

Step Editor (right panel)

  • Appears when a node is selected
  • Edit the node name, change its shape
  • Manage branches / answer options (add, remove, reorder)
  • Question variant shows connection status per answer

Context menu (right-click)

  • On canvas: Add node at cursor, Re-center, Undo, Redo
  • On node: Rename, Duplicate, Disconnect all edges, Delete
  • On edge: Style (solid/dashed/dotted), Arrowhead, Reset routing, Delete
  • On touch devices: long-press the canvas (~550ms) opens the canvas menu

Keyboard shortcuts

ShortcutAction
Ctrl+ZUndo
Ctrl+Y / Ctrl+Shift+ZRedo
Ctrl+0Fit all nodes in view
Ctrl+C / Ctrl+VCopy and paste the current selection (internal edges preserved, +24 px offset on paste)
Ctrl+DDuplicate the current selection
Delete / BackspaceRemove the current selection
EscapeDeselect, cancel in-flight edge drag, close context menu
Arrow keysNudge selection by 1 grid unit (Shift = 4 units)
Alt+ArrowTraverse to the nearest node in that direction from the current selection
Shift+clickToggle a node in/out of the current selection
Shift+drag (empty canvas)Box-select โ€” add every intersected node to the selection
Double-click edge labelRename the edge label inline
Drag edge midpointRoute the edge through a waypoint (right-click โ†’ Reset routing to clear)

Theming

// Force dark
<fsd-diagram [theme]="'dark'" />

// Force light
<fsd-diagram [theme]="'light'" />

// Follow system prefers-color-scheme (default)
<fsd-diagram [theme]="'auto'" />

To match the editor to a host application's brand, pass themeOverrides โ€” a Partial<ThemeColors> that is shallow-merged on top of the resolved light/dark palette:

import { Component } from '@angular/core';
import { FsdDiagramComponent } from '@flowchart-sequence-designer/angular';
import type { ThemeColors } from '@flowchart-sequence-designer/angular';

@Component({
  standalone: true,
  imports: [FsdDiagramComponent],
  template: `<fsd-diagram [theme]="'dark'" [themeOverrides]="brand" />`,
})
export class BrandedComponent {
  brand: Partial<ThemeColors> = {
    canvas: '#0b1020',
    nodeFill: '#111a2e',
    nodeStroke: '#2b3a5a',
    nodeSelectedFill: '#1a2447',
    edgeColor: '#7b8aa6',
    textPrimary: '#e6edf7',
  };
}

ThemeColors token groups (flowchart)

Token groupMembersWhere it shows up
Canvascanvas, dotBackground + dot grid
NodesnodeFill, nodeStroke, nodeSelectedFillNode body, border, selection tint
EdgesedgeColorEdge stroke + arrowhead
Type ramptextPrimary, textSecondary, textMutedLabels, hints, secondary text
Chrome โ€” panelpanelBg, panelBorderSide panel surface
Chrome โ€” controlsctrlsBg, ctrlsBorderToolbar, zoom controls
Chrome โ€” inputinputBg, inputBorder, inputTextForm fields in the side panel
Chrome โ€” cardcardBg, cardBorderAnswer rows, branch rows
Chrome โ€” sectionsectionBorderDivider between panel sections
ButtonsbtnSecBg, btnSecText, shapeBtnBg, shapeBtnBorderSecondary buttons, shape picker
AccentsaddFormBg, bannerBg, labelText, hintText, statusBgAdd-form backdrop, validation banner

SequenceThemeColors (sequence)

The sequence editor accepts the same [themeOverrides] input with a slightly different shape โ€” Partial<SequenceThemeColors>. It drops node-specific tokens and adds lifeline, arrow, and actorFill / actorStroke / actorText for the swim-lane elements.


Restricting exports and import

// Only allow JSON and SVG download
<fsd-diagram [allowedExports]="['json', 'svg']" />

// Hide the import button entirely
<fsd-diagram [allowImport]="false" />

// Handle exports yourself (e.g. send to an API)
<fsd-diagram
  (exportEvent)="handleExport($event)"
/>
// In component: handleExport(e: { format: string; content: string | Blob }) { ... }

Accessibility & touch

The editor is keyboard-first and screen-reader-aware. Every interaction reachable by mouse has a keyboard equivalent; every state change announces via a polite aria-live region.

Keyboard navigation โ€” Every node, port, and toolbar control is reachable with Tab; selection moves with Arrow keys (1 grid unit, or 4 with Shift); Alt+Arrow traverses the graph to the nearest connected neighbor in that direction. The focus ring is visible at all times.

ARIA roles โ€” The canvas is an application region with an aria-label; selection, add, and delete actions update an aria-live="polite" status region announced as "Selected {label}", "Added node {label}", etc. The toolbar uses native <button> elements with explicit labels.

Reduced motion โ€” The animated edge-flow dash honours prefers-reduced-motion โ€” when set, the dash freezes and the canvas renders with no animation.

Touch interactions:

ActionGesture
PanOne-finger drag on the canvas background
ZoomTwo-finger pinch
Context menuLong-press (~550 ms) on the canvas or on a node
Larger hit targetsPort circles auto-enlarge on coarse-pointer devices (24 px vs. 14 px on mouse)
Drag nodePress and drag the node body. The 8 px drag threshold lets you tap to select without nudging.

Security

This package uses the same core editor as the React version, which takes security seriously:

  • Input sanitization โ€” All user-provided text is sanitized before rendering (HTML tags, javascript:/data:/vbscript: URIs, on* event handlers, and control characters are stripped).
  • Resource limits โ€” Importers enforce hard caps (500 nodes, 2000 edges, 100 actors, 2000 messages, 2MB input) to prevent resource exhaustion.
  • Prototype pollution defense โ€” JSON importer strips __proto__, constructor, and prototype keys recursively.
  • SVG export โ€” Defence-in-depth: sanitize first, then XML-escape. Safe even if consumed by less-strict parsers.
  • No eval / innerHTML โ€” The codebase never uses dynamic code execution or raw HTML injection.
  • CodeQL โ€” Automated security scanning runs weekly and on every PR.
  • Dependabot โ€” Dependency updates monitored weekly.

Framework Wrappers

FrameworkPackageDocs
Reactflowchart-sequence-designerDocs & Demo
Angular@flowchart-sequence-designer/angularDocs & Demo
Vue@flowchart-sequence-designer/vueDocs & Demo

Re-exported Types

For convenience, common types are re-exported so you don't need a separate import:

import type {
  DiagramModel,
  DiagramNode,
  DiagramEdge,
  DiagramType,
  DiagramVariant,
  ExportFormat,
  NodeShape,
  SequenceMessage,
  DiagramEditorProps,
  SequenceEditorProps,
  ThemeColors,
  SequenceThemeColors,
} from '@flowchart-sequence-designer/angular';

DiagramModel

interface DiagramModel {
  type: 'flowchart' | 'sequence';
  variant?: DiagramVariant;    // 'flowchart' | 'question' | 'journey' (flowchart-type only)
  title?: string;
  nodes: DiagramNode[];        // always present (empty array for sequence models)
  edges: DiagramEdge[];        // always present (empty array for sequence models)
  actors?: string[];           // sequence models only โ€” ordered actor names
  messages?: SequenceMessage[]; // sequence models only โ€” ordered messages
}

DiagramNode

interface DiagramNode {
  id: string;
  label: string;
  shape?: 'rectangle' | 'diamond' | 'circle' | 'parallelogram';
  x?: number;
  y?: number;
  metadata?: Record<string, unknown>;
  // question variant: metadata.answers = string[]
}

DiagramEdge

interface DiagramEdge {
  id: string;
  from: string;
  to: string;
  label?: string;
  style?: 'solid' | 'dashed' | 'dotted';
  arrowhead?: 'arrow' | 'none' | 'open';
  waypoint?: { x: number; y: number }; // manual routing point (JSON only)
}

SequenceMessage

interface SequenceMessage {
  id: string;
  from: string;            // actor name
  to: string;              // actor name
  label: string;
  style?: 'solid' | 'dashed';
}

ValidationError

interface ValidationError {
  kind: 'dangling-from' | 'dangling-to' | 'duplicate-node-id' | 'duplicate-edge-id';
  id: string;
  message: string;
}

Architecture

This wrapper uses a lightweight React Bridge pattern:

  1. Each Angular component creates a React root inside its template <div>
  2. Angular @Input() values are mapped to React props
  3. React onChange/onExport callbacks are wrapped in NgZone.run() to trigger Angular change detection
  4. React internal renders run outside Angular's zone (no unnecessary CD cycles)
  5. On ngOnDestroy, the React root is cleanly unmounted

Performance Considerations

  • OnPush compatible โ€” all components use ChangeDetectionStrategy.OnPush
  • Zone-optimized โ€” React renders don't trigger Angular's zone; only explicit outputs do
  • Lazy-loaded โ€” the React editor is loaded via dynamic import() (code-split friendly)
  • Minimal overhead โ€” the bridge is ~1KB; React+ReactDOM peer deps add ~45KB gzipped

Package structure

@flowchart-sequence-designer/angular/
โ”œโ”€โ”€ dist/
โ”‚   โ”œโ”€โ”€ index.js / index.d.ts        โ† Angular components + re-exports
โ”‚   โ””โ”€โ”€ public-api.ts                โ† barrel export
โ””โ”€โ”€ src/
    โ”œโ”€โ”€ lib/
    โ”‚   โ”œโ”€โ”€ fsd-diagram.component.ts  # <fsd-diagram> (flowchart/question/journey)
    โ”‚   โ”œโ”€โ”€ fsd-sequence.component.ts # <fsd-sequence>
    โ”‚   โ”œโ”€โ”€ fsd-toolbar.component.ts  # <fsd-toolbar>
    โ”‚   โ””โ”€โ”€ fsd-step-editor.component.ts # <fsd-step-editor>
    โ””โ”€โ”€ public-api.ts                 # types + component re-exports

Building from source

npm install
npm run build        # library โ†’ dist/
cd demo && npx ng build   # demo app
npm test             # unit tests

Requirements

  • Angular 16+ (standalone components)
  • flowchart-sequence-designer โ‰ฅ 1.2.0
  • react & react-dom โ‰ฅ 18

License

MIT