Keyboard Shortcuts
The keyboard shortcuts system in ngDiagram lets users perform common actions quickly using customizable key combinations. It supports platform-specific modifier keys (automatically handling Ctrl/Cmd differences), multiple shortcuts per action, and dynamic runtime updates.
Available Actions
Section titled “Available Actions”All available shortcut actions with their default key bindings. See ShortcutActionName for the complete type reference.
| Action | Default Shortcut | Description |
|---|---|---|
copy | Ctrl/Cmd + C | Copy selected elements to clipboard |
cut | Ctrl/Cmd + X | Cut selected elements to clipboard |
paste | Ctrl/Cmd + V | Paste elements from clipboard |
deleteSelection | Delete or Backspace | Delete currently selected elements |
selectAll | Ctrl/Cmd + A | Select all elements in the diagram |
boxSelection | Shift held | Enable box selection mode (pointer only) |
multiSelection | Ctrl/Cmd held | Multi-selection mode (pointer only) |
keyboardMoveSelectionUp | ↑ | Move selected elements up |
keyboardMoveSelectionDown | ↓ | Move selected elements down |
keyboardMoveSelectionLeft | ← | Move selected elements left |
keyboardMoveSelectionRight | → | Move selected elements right |
keyboardPanUp | ↑ | Pan viewport up |
keyboardPanDown | ↓ | Pan viewport down |
keyboardPanLeft | ← | Pan viewport left |
keyboardPanRight | → | Pan viewport right |
undo | Ctrl/Cmd + Z | Undo last action (not implemented by default; requires custom model) |
redo | Ctrl/Cmd + Y | Redo last undone action (not implemented by default; requires custom model) |
Basic Usage
Section titled “Basic Usage”To override, disable, or extend default shortcuts, use the configureShortcuts() helper:
import { configureShortcuts } from 'ng-diagram';
const config = { shortcuts: configureShortcuts([ // Override: Change paste to Ctrl+B { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }], }, // Disable: Empty bindings array { actionName: 'undo', bindings: [], }, // Multiple bindings: WSAD + Arrow keys { actionName: 'keyboardMoveSelectionUp', bindings: [{ key: 'w' }, { key: 'ArrowUp' }], }, ]),};You can also merge custom shortcuts with existing ones at runtime:
// Get current shortcuts from the serviceconst currentShortcuts = ngDiagramService.config().shortcuts;
// Merge custom shortcuts with existing onesconst updatedShortcuts = configureShortcuts( [ { actionName: 'paste', bindings: [{ key: 'b', modifiers: { primary: true } }], }, ], currentShortcuts // Pass existing shortcuts as base);
// Update the configurationngDiagramService.updateConfig({ shortcuts: updatedShortcuts });configureShortcuts(customShortcuts, baseShortcuts?) merges your custom shortcuts with defaults:
- First parameter: Custom shortcuts (overrides actions with matching
actionName) - Second parameter: Optional base shortcuts. Defaults are used if omitted.
- Returns: A merged shortcuts array
Unspecified actions retain their existing shortcuts.
Configuration Reference
Section titled “Configuration Reference”Shortcut Structure
Section titled “Shortcut Structure”Keyboard and pointer shortcuts in ngDiagram are defined through the ShortcutDefinition interface. A shortcut definition maps an action name to one or more key bindings (keyboard or modifier-only combinations).
Each shortcut may include:
- One or more keyboard bindings (e.g., Ctrl + C)
- Or one or more modifier-only bindings (e.g., Shift + click for box selection)
See ShortcutDefinition API reference.
Available Modifiers
Section titled “Available Modifiers”interface InputModifiers { primary: boolean; // Ctrl (Windows/Linux) OR Cmd (macOS) - auto-normalized secondary: boolean; // Alt key shift: boolean; // Shift key meta: boolean; // Windows key or Cmd key}Platform normalization:
The primary modifier automatically maps to Ctrl on Windows/Linux and Cmd on macOS,
allowing you to define shortcuts once that work seamlessly across platforms.
Key Names
Section titled “Key Names”Use standard browser key names: 'a', 'b', 'Delete', 'Backspace', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', etc. Keys are case-sensitive.
See MDN KeyboardEvent.key documentation for the complete list of valid key values.
Modifier-Only Shortcuts
Section titled “Modifier-Only Shortcuts”Modifier-only shortcuts (bindings without a key) are used for pointer-based interactions,
such as holding Shift for box selection.
{ modifiers: { shift: true, }} // Matches when Shift held during clickThese shortcuts ensure that typing keys won’t accidentally trigger diagram actions.
Example
Section titled “Example”import '@angular/compiler';import { Component } from '@angular/core';import { NgDiagramModelService, provideNgDiagram } from 'ng-diagram';import { DiagramComponent } from './diagram.component';
@Component({ imports: [DiagramComponent], template: `<shortcut-manager-example></shortcut-manager-example> `, styles: [ ` :host { display: flex; position: relative; } `, ], providers: [NgDiagramModelService, provideNgDiagram()],})export class DiagramWrapperComponent {}import '@angular/compiler';import { Component } from '@angular/core';import { configureShortcuts, initializeModel, NgDiagramBackgroundComponent, NgDiagramComponent, NgDiagramViewportService, type NgDiagramConfig,} from 'ng-diagram';import { ShortcutButtonsComponent } from './shortcut-buttons/shortcut-buttons.component';
@Component({ selector: 'shortcut-manager-example', imports: [ NgDiagramComponent, NgDiagramBackgroundComponent, ShortcutButtonsComponent, ], template: ` <div class="not-content diagram"> <ng-diagram [model]="model" [config]="config"> <ng-diagram-background /> </ng-diagram> </div> <shortcut-buttons /> `, styleUrl: './diagram.component.scss', providers: [NgDiagramViewportService],})export class DiagramComponent { config = { zoom: { zoomToFit: { onInit: true, padding: 100, }, }, shortcuts: configureShortcuts([ // Custom keyboard shortcuts for moving selection { actionName: 'keyboardMoveSelectionUp', bindings: [{ key: 'w' }, { key: 'ArrowUp' }], }, { actionName: 'keyboardMoveSelectionDown', bindings: [{ key: 's' }, { key: 'ArrowDown' }], }, { actionName: 'keyboardMoveSelectionLeft', bindings: [{ key: 'a' }, { key: 'ArrowLeft' }], }, { actionName: 'keyboardMoveSelectionRight', bindings: [{ key: 'd' }, { key: 'ArrowRight' }], }, ]), } satisfies NgDiagramConfig;
model = initializeModel({ nodes: [ { id: '1', position: { x: 100, y: 100 }, data: { label: 'Node 1', }, }, { id: '2', position: { x: 400, y: 100 }, data: { label: 'Node 2', }, }, { id: '3', position: { x: 250, y: 300 }, data: { label: 'Node 3', }, }, ], });}import { Component, inject, signal } from '@angular/core';import { configureShortcuts, NgDiagramService, type ShortcutDefinition,} from 'ng-diagram';
@Component({ imports: [], selector: 'shortcut-buttons', template: ` <label class="checkbox-label"> <input type="checkbox" [checked]="useCustomShortcut()" (change)="togglePasteShortcut()" /> <span>Use Ctrl/Cmd + B for paste</span> </label> `, styleUrls: ['./shortcut-buttons.component.scss'],})export class ShortcutButtonsComponent { private readonly ngDiagramService = inject(NgDiagramService); protected readonly useCustomShortcut = signal(false);
togglePasteShortcut(): void { this.useCustomShortcut.update((value) => !value);
const currentShortcuts = this.ngDiagramService.config() .shortcuts as ShortcutDefinition[]; const updatedShortcuts = configureShortcuts( [ { actionName: 'paste', bindings: [ { key: this.useCustomShortcut() ? 'b' : 'v', modifiers: { primary: true }, }, ], }, ], currentShortcuts );
this.ngDiagramService.updateConfig({ shortcuts: updatedShortcuts, }); }}:host { position: relative; width: 100%; height: 100%; display: block; // needed for flex children to work, otherwise children renders outside of host}
.diagram { display: flex; height: var(--ng-diagram-height); border: var(--ng-diagram-border); margin-top: 0;}:host { position: absolute; right: 1rem; top: 1rem; display: flex; background-color: var(--ngd-node-bg-primary-default); border: var(--ng-diagram-border); margin-top: 0;
.checkbox-label { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; border-radius: 0.25rem; user-select: none; cursor: pointer;
input[type='checkbox'] { width: 1rem; height: 1rem; cursor: pointer; }
span { font-size: 0.875rem; } }}