Getting Started
Overview
Installation
Theme
Forms
Basic Inputs
Custom Inputs
Select
Components
Components
78
Micro Charts
Navigation
Libraries
Content Editor
Data View
Form Builder
Headless Editor
Image Designer
Kanban Board
PDF Builder
PDF Signer
PDF Viewer
Video Player
GitHub repositoryGitHub starsGitHub forksNgStarter UI npm versionNgStarter UI npm downloads per month

Commands and Toolbar

A command is a typed object that performs an editing operation and reports whether it is enabled and active. Commands drive toolbars, menus, and key bindings in the same way.

Loading example…

The command contract

export interface NgsHeadlessEditorCommand<TPayload = void> {
  readonly id: string;
  execute(editor: NgsHeadlessEditor, payload: TPayload): boolean;
  enabled?(editor: NgsHeadlessEditor, payload: TPayload): boolean;
  active?(editor: NgsHeadlessEditor, payload: TPayload): boolean;
}

const toggleHeading: NgsHeadlessEditorCommand = {
  id: 'toggle-heading',
  execute: editor => editor.toggleBlock('heading'),
  active: editor => editor.isBlockActive('heading')
};

const undo: NgsHeadlessEditorCommand = {
  id: 'undo',
  execute: editor => editor.undo(),
  enabled: editor => editor.canUndo()
};
MemberDescription
idUnique id. Registered commands can be executed and bound by id.
execute(editor, payload)Performs the change and returns whether it did anything.
enabled(editor, payload)Optional. When it returns false, execute is not called and bound controls are disabled.
active(editor, payload)Optional. Drives the pressed state of toggle controls.

Predicates read editor signals, so the state of every bound control updates automatically when the selection or the document changes. All commands are disabled while the editor is read-only. Use editor.canApplyMark(type) in enabled for formatting commands and editor.canEditBlocks() for block commands: formatting commands also work inside nested editors such as table cells, block commands do not. See Formatting everywhere.

Payloads

The second type parameter describes the payload. Pass it with commandData in templates, as the second argument of execute(), or as payload in a key binding.

const setBlockType: NgsHeadlessEditorCommand<string> = {
  id: 'set-block-type',
  execute: (editor, type) => !editor.isBlockActive(type) && editor.toggleBlock(type),
  active: (editor, type) => editor.isBlockActive(type)
};

Toolbar controls

ngsHeadlessEditorCommand turns any element into a command control:

  • prevents the default mousedown, so the text selection is kept when the control is pressed;
  • executes the command on click;
  • adds the active class and aria-pressed from active();
  • sets disabled from enabled() and the read-only state.
<div role="toolbar" aria-label="Formatting">
  <button ngsIconButton aria-label="Bold" [ngsHeadlessEditorCommand]="bold">
    <ngs-icon name="fluent:text-bold-24-regular"/>
  </button>
  <button ngsButton="outlined" [ngsHeadlessEditorCommand]="setBlockType" commandData="heading">
    Heading
  </button>
  <button ngsButton="outlined" [ngsHeadlessEditorCommand]="setTextColor" commandData="#dc2626">
    Red
  </button>

  <!-- the directive is exported as ngsHeadlessEditorCommand -->
  <button #italicControl="ngsHeadlessEditorCommand" [ngsHeadlessEditorCommand]="italic">
    Italic {{ italicControl.active() ? '(on)' : '' }}
  </button>
</div>

<!-- .active { background: var(--ngs-state-selected-bg); } -->

Controls that call editor methods directly, instead of a command, should prevent mousedown themselves to keep the selection.

Running commands from code

editor.execute(NGS_HEADLESS_EDITOR_TOGGLE_BOLD);           // by object
editor.execute('toggle-bold');                             // by registered id
editor.execute(NGS_HEADLESS_EDITOR_SET_TEXT_COLOR, '#dc2626');

editor.isCommandEnabled(NGS_HEADLESS_EDITOR_SET_TEXT_COLOR, 'red; x'); // false
editor.isCommandActive(NGS_HEADLESS_EDITOR_TOGGLE_BOLD);

Key bindings

Plugins declare keymap entries. A key is written as modifiers followed by the key, joined by dashes: Mod (Ctrl or Cmd), Alt, Shift, then a character or a key name such as Enter or ArrowUp. Matching is case-insensitive.

defineNgsHeadlessEditorPlugin({
  id: 'shortcuts',
  commands: [toggleHeading],
  keymap: [
    { key: 'Mod-Alt-2', command: toggleHeading },
    { key: 'Mod-Shift-9', command: 'toggle-quote' },          // by id
    { key: 'Mod-Shift-h', command: NGS_HEADLESS_EDITOR_SET_BACKGROUND_COLOR, payload: '#fef08a' }
  ]
});

Bindings are matched against the typed character first and the physical key second, so Mod-b works on a Cyrillic layout, Mod-Shift-7 works although Shift+7 types an ampersand, and Mod-Alt-c works on macOS where Option+C types a different character. The first binding found in plugin order wins.

Built-in commands

CommandPluginShortcut
NGS_HEADLESS_EDITOR_TOGGLE_BOLDbasicTextEditorPluginMod-b
NGS_HEADLESS_EDITOR_TOGGLE_ITALICbasicTextEditorPluginMod-i
NGS_HEADLESS_EDITOR_TOGGLE_STRIKEbasicTextEditorPluginMod-Shift-x
NGS_HEADLESS_EDITOR_TOGGLE_CODEbasicTextEditorPluginMod-e
NGS_HEADLESS_EDITOR_SET_TEXT_COLORcolorEditorPluginpayload: CSS color
NGS_HEADLESS_EDITOR_UNSET_TEXT_COLORcolorEditorPlugin—
NGS_HEADLESS_EDITOR_SET_BACKGROUND_COLORcolorEditorPluginpayload: CSS color
NGS_HEADLESS_EDITOR_UNSET_BACKGROUND_COLORcolorEditorPlugin—

Undo and redo are handled by the editor itself: Mod-z, Mod-Shift-z, and Mod-y.