Skip to content

NotectlEditor

NotectlEditor is the <notectl-editor> Web Component — the public entry point to the editor.

import { createEditor } from '@notectl/core';
const editor = await createEditor({
placeholder: 'Start typing...',
autofocus: true,
});
document.body.appendChild(editor);
const editor = document.createElement('notectl-editor') as NotectlEditor;
document.body.appendChild(editor);
await editor.init({ placeholder: 'Start typing...' });
interface NotectlEditorConfig {
/** Controls which inline marks are enabled (auto-configures TextFormattingPlugin). */
features?: Partial<TextFormattingConfig>;
/** Plugins to register (headless mode — no toolbar). */
plugins?: readonly Plugin[];
/** Declarative toolbar layout — shorthand array or full ToolbarConfig. */
toolbar?: ReadonlyArray<ReadonlyArray<Plugin>> | ToolbarConfig;
/** Placeholder text shown when editor is empty. */
placeholder?: string;
/** Read-only mode. */
readonly?: boolean;
/** Focus the editor on initialization. */
autofocus?: boolean;
/** Maximum undo history depth. */
maxHistoryDepth?: number;
/** Theme preset or custom Theme object. Defaults to ThemePreset.Light. */
theme?: ThemePreset | Theme;
/** Optional nonce for fallback runtime <style> elements. */
styleNonce?: string;
/** Paper size for WYSIWYG page layout. When set, content renders at exact paper width. */
paperSize?: PaperSize;
/** Document-level text direction. When set, applies `dir` on the content element. */
dir?: 'ltr' | 'rtl';
/** Editor locale. Defaults to Locale.BROWSER (auto-detect from navigator.language). */
locale?: Locale;
}

When you need control over responsive overflow behavior, pass a ToolbarConfig object instead of the shorthand array:

interface ToolbarConfig {
/** Plugin groups defining toolbar layout. */
readonly groups: ReadonlyArray<ReadonlyArray<Plugin>>;
/** Responsive overflow behavior. Default: ToolbarOverflowBehavior.BurgerMenu */
readonly overflow?: ToolbarOverflowBehavior;
}
import { createEditor } from '@notectl/core';
import { ToolbarOverflowBehavior } from '@notectl/core/plugins/toolbar';
const editor = await createEditor({
toolbar: {
groups: [
[new TextFormattingPlugin()],
[new HeadingPlugin()],
],
overflow: ToolbarOverflowBehavior.Flow,
},
});

See the Toolbar Configuration guide for details on overflow modes.

Returns the document as a JSON-serializable Document object.

Replaces the editor content with the given document.

getContentHTML(options?): Promise<string | ContentCSSResult>

Section titled “getContentHTML(options?): Promise<string | ContentCSSResult>”

Returns sanitized HTML representation of the document. The return type depends on the options:

// Default — returns inline-styled HTML string
const html = await editor.getContentHTML();
// Pretty-printed — returns indented HTML string
const pretty = await editor.getContentHTML({ pretty: true });
// Class-based CSS mode — returns { html, css, styleMap } object
const { html, css } = await editor.getContentHTML({ cssMode: 'classes' });
const { html, css } = await editor.getContentHTML({ cssMode: 'classes', pretty: true });
getContentHTML(): Promise<string>;
getContentHTML(options: { pretty?: boolean }): Promise<string>;
getContentHTML(options: ContentHTMLOptions & { cssMode: 'classes' }): Promise<ContentCSSResult>;
interface ContentHTMLOptions {
readonly pretty?: boolean;
readonly cssMode?: CSSMode; // 'inline' (default) | 'classes'
}
interface ContentCSSResult {
readonly html: string; // HTML with class attributes instead of inline styles
readonly css: string; // Collected CSS rules for the classes used
readonly styleMap: ReadonlyMap<string, string>; // Maps class names to CSS declarations for round-trip
}

When cssMode: 'classes' is set, dynamic marks (text color, highlight, font size, font family) are serialized as CSS class names instead of inline style attributes. This is useful for rendering exported HTML in strict CSP environments where style-src-attr: 'none' blocks inline styles.

const { html, css } = await editor.getContentHTML({ cssMode: 'classes' });
// html: '<p class="notectl-align-center"><strong><span class="notectl-s0">Hello</span></strong></p>'
// css: '.notectl-s0 { color: #ff0000; }\n.notectl-align-center { text-align: center; }'

Identical style combinations are deduplicated — multiple elements with the same styles share a single class name and CSS rule.

See the CSP guide for integration examples.

setContentHTML(html: string, options?: SetContentHTMLOptions): Promise<void>

Section titled “setContentHTML(html: string, options?: SetContentHTMLOptions): Promise<void>”

Parses HTML and sets it as the editor content.

Each serialized block carries a data-block-id attribute (part of the wire format). When setContentHTML parses HTML produced by getContentHTML, those IDs are adopted so block identity round-trips — this is what keeps the caret stable when an external owner (Angular signal form, RxJS pipe, …) writes back the same content on every keystroke. Externally pasted HTML without data-block-id works as before; fresh IDs are generated. See Round-Trip Identity.

Returns plain text content (blocks joined by \n).

Replaces editor content from plain text. Each \n becomes a paragraph.

editor.setText('First paragraph\nSecond paragraph');

Existing top-level block IDs are reused in document order, so the caret survives setText(getText()) round-trips. When value equals the current text, the call is a no-op — selection and history remain untouched. See Round-Trip Identity.

Returns true if the editor contains only a single empty paragraph.

Object with convenience methods for common operations. These are a fixed set of shortcuts — for plugin-registered commands, use executeCommand():

editor.commands.toggleBold();
editor.commands.toggleItalic();
editor.commands.toggleUnderline();
editor.commands.undo();
editor.commands.redo();
editor.commands.selectAll();

Returns an object that checks if the built-in convenience commands can be executed. For plugin-registered commands, use executeCommand() directly.

const can = editor.can();
can.toggleBold(); // boolean
can.toggleItalic(); // boolean
can.toggleUnderline(); // boolean
can.undo(); // boolean
can.redo(); // boolean
can.selectAll(); // boolean

Executes a named command registered by any plugin. Returns true if handled.

Returns whether a named command can be executed.

editor.executeCommand('toggleStrikethrough');
editor.executeCommand('insertHorizontalRule');

configurePlugin(pluginId: string, config: PluginConfig): void

Section titled “configurePlugin(pluginId: string, config: PluginConfig): void”

Updates a plugin’s configuration at runtime.

Returns the current immutable editor state.

Returns the current read-only state.

if (editor.isReadOnly) {
console.log('Editor is in read-only mode');
}

Dispatches a transaction through the middleware chain.

In read-only mode, mutating transactions are silently dropped at the view layer. Selection-only transactions and transactions flagged via TransactionBuilder.readonlyAllowed() (used by opt-in features like checklist toggling) still apply. This guard is centralized in the view, so plugin-side NodeView controls (e.g. table delete/add-row buttons, code-block delete) are inert in read-only mode without per-plugin code.

Note: low-level state replacement APIs (setJSON, setHTML, replaceState) bypass dispatch and the read-only guard — they always succeed.

Subscribe to an event.

Unsubscribe from an event.

EventPayloadDescription
stateChange{ oldState, newState, transaction }Every state change
selectionChange{ selection: EditorSelection }Cursor/selection moved
focusundefinedEditor gained focus
blurundefinedEditor lost focus
readyundefinedInitialization complete

getService<T>(key: ServiceKey<T>): T | undefined

Section titled “getService<T>(key: ServiceKey<T>): T | undefined”

Retrieves a typed service registered by any plugin. Returns undefined if not found.

import { TableSelectionServiceKey } from '@notectl/core/plugins/table';
const tableService = editor.getService(TableSelectionServiceKey);
tableService?.getSelectedCells();

onPluginEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void

Section titled “onPluginEvent<T>(key: EventKey<T>, callback: PluginEventCallback<T>): () => void”

Subscribes to typed plugin events from outside the plugin system. Returns an unsubscribe function.

import { BEFORE_PRINT, AFTER_PRINT } from '@notectl/core/plugins/print';
const unsubscribe = editor.onPluginEvent(BEFORE_PRINT, () => {
console.log('Printing...');
});
// Later: unsubscribe();

setTheme(theme: ThemePreset | Theme): void

Section titled “setTheme(theme: ThemePreset | Theme): void”

Changes the theme at runtime. Accepts a preset string ('light', 'dark', 'system') or a custom Theme object.

import { ThemePreset } from '@notectl/core';
editor.setTheme(ThemePreset.Dark);
editor.setTheme(myCustomTheme);

Returns the current theme setting.

See the Theming guide for full details on presets, custom themes, and CSS custom properties.

Returns the currently configured paper size, or undefined if the editor uses fluid layout.

import { PaperSize } from '@notectl/core';
editor.configure({ paperSize: PaperSize.DINA4 });
editor.getPaperSize(); // 'din-a4'

See the Paper Size guide for full details on WYSIWYG page layout and print integration.

Sets the editor language for all plugins. Defaults to Locale.BROWSER which auto-detects from navigator.language.

import { createEditor, Locale } from '@notectl/core';
const editor = await createEditor({
locale: Locale.DE,
toolbar: [/* ... */],
});

See the Internationalization guide for full details on global and per-plugin locale configuration, custom locales, and available languages.

Returns a promise that resolves when the editor is fully initialized.

configure(config: Partial<NotectlEditorConfig>): void

Section titled “configure(config: Partial<NotectlEditorConfig>): void”

Updates configuration at runtime. Active side-effects for placeholder, readonly, paperSize, and dir. To change the theme at runtime, use setTheme() instead.

styleNonce is accepted in configure() but evaluated during initialization.

Registers a plugin. Must be called before init() or before the element is added to the DOM. Throws if called after initialization.

Cleans up the editor. The editor can be re-initialized after destruction.

AttributeDescription
placeholderPlaceholder text (reflected)
readonlyRead-only mode (reflected)
themeTheme preset: "light", "dark", or "system"
paper-sizePaper size: "din-a4", "din-a5", "us-letter", or "us-legal"
dirText direction: "ltr" or "rtl"