

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.
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()
};| Member | Description |
|---|---|
id | Unique 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.
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)
};ngsHeadlessEditorCommand turns any element into a command control:
mousedown, so the text selection is kept when the control is pressed;active class and aria-pressed from active();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.
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); 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.
| Command | Plugin | Shortcut |
|---|---|---|
NGS_HEADLESS_EDITOR_TOGGLE_BOLD | basicTextEditorPlugin | Mod-b |
NGS_HEADLESS_EDITOR_TOGGLE_ITALIC | basicTextEditorPlugin | Mod-i |
NGS_HEADLESS_EDITOR_TOGGLE_STRIKE | basicTextEditorPlugin | Mod-Shift-x |
NGS_HEADLESS_EDITOR_TOGGLE_CODE | basicTextEditorPlugin | Mod-e |
NGS_HEADLESS_EDITOR_SET_TEXT_COLOR | colorEditorPlugin | payload: CSS color |
NGS_HEADLESS_EDITOR_UNSET_TEXT_COLOR | colorEditorPlugin | — |
NGS_HEADLESS_EDITOR_SET_BACKGROUND_COLOR | colorEditorPlugin | payload: CSS color |
NGS_HEADLESS_EDITOR_UNSET_BACKGROUND_COLOR | colorEditorPlugin | — |
Undo and redo are handled by the editor itself: Mod-z, Mod-Shift-z, and Mod-y.