Skip to content

Toolbar Plugin

The ToolbarPlugin renders the editor toolbar UI. It is automatically created when you use the toolbar configuration option — you don’t need to instantiate it manually.

Full toolbar

const editor = await createEditor({
toolbar: [
[new TextFormattingPlugin()],
[new HeadingPlugin()],
],
});
// ToolbarPlugin is automatically created and registered

Each inner array becomes a visual toolbar group separated by dividers.

For advanced use cases, you can create the ToolbarPlugin manually:

import { ToolbarPlugin } from '@notectl/core';
const toolbar = new ToolbarPlugin({
groups: [['text-formatting'], ['heading']],
});
const editor = await createEditor({
plugins: [
new TextFormattingPlugin(),
new HeadingPlugin(),
toolbar,
],
});
interface ToolbarLayoutConfig {
/** Plugin ID groups — each inner array is a visual toolbar group */
readonly groups: ReadonlyArray<ReadonlyArray<string>>;
/** Controls responsive overflow. Default: ToolbarOverflowBehavior.BurgerMenu */
readonly overflow?: ToolbarOverflowBehavior;
}

The overflow field controls how items behave when the toolbar is too narrow. See the Toolbar Configuration guide for the available modes (BurgerMenu, Flow, None).

Plugins register toolbar items via context.registerToolbarItem():

interface ToolbarItemBase {
/** Unique identifier. */
readonly id: string;
/** Logical group for auto-grouping (e.g., 'format', 'block'). */
readonly group: string;
/** HTML string for the button icon. */
readonly icon: string;
/** Accessible label for screen readers. */
readonly label: string;
/** Tooltip text shown on hover. */
readonly tooltip?: string;
/** Command to execute on click. */
readonly command: string;
/**
* Ordering within group (lower = further left).
* @deprecated Use the declarative `toolbar` config on `createEditor()` instead.
*/
readonly priority?: number;
/**
* Render a separator after this button.
* @deprecated Use the declarative `toolbar` config on `createEditor()` instead.
*/
readonly separatorAfter?: boolean;
/** Returns true when the item should appear active/pressed. */
isActive?(state: EditorState): boolean;
/** Returns true when the item should be enabled. */
isEnabled?(state: EditorState): boolean;
}
// Discriminated union — popupType determines which extra fields are available:
interface ToolbarItemGridPicker extends ToolbarItemBase {
readonly popupType: 'gridPicker';
readonly popupConfig: GridPickerConfig;
}
interface ToolbarItemDropdown extends ToolbarItemBase {
readonly popupType: 'dropdown';
readonly popupConfig: DropdownConfig;
}
interface ToolbarItemCustomPopup extends ToolbarItemBase {
readonly popupType: 'custom';
/** Called to render arbitrary popup content. Use onClose() to dismiss. */
renderPopup(container: HTMLElement, context: PluginContext, onClose: () => void): void;
}
interface ToolbarItemNoPopup extends ToolbarItemBase {
readonly popupType?: undefined;
}
type ToolbarItem =
| ToolbarItemNoPopup
| ToolbarItemGridPicker
| ToolbarItemDropdown
| ToolbarItemCustomPopup;
TypeDescriptionUsed By
dropdownVertical list of optionsHeadingPlugin, AlignmentPlugin
gridPicker2D grid for dimension selectionTablePlugin
customFull control over popup renderingFontPlugin, FontSizePlugin, TextColorPlugin, LinkPlugin

getOverflowBehavior(): ToolbarOverflowBehavior

Section titled “getOverflowBehavior(): ToolbarOverflowBehavior”

Returns the current overflow behavior mode.

setOverflowBehavior(behavior: ToolbarOverflowBehavior): void

Section titled “setOverflowBehavior(behavior: ToolbarOverflowBehavior): void”

Switches the overflow behavior at runtime. Triggers an immediate re-layout.

import { ToolbarOverflowBehavior } from '@notectl/core';
// Switch to flow mode at runtime
toolbarPlugin.setOverflowBehavior(ToolbarOverflowBehavior.Flow);

The toolbar exposes a typed service for programmatic control:

import { ToolbarServiceKey } from '@notectl/core';
const toolbarService = context.getService(ToolbarServiceKey);
// Force refresh of all button states
toolbarService.refresh();
interface ToolbarServiceAPI {
/** Re-reads isActive/isEnabled from state and updates all buttons. */
refresh(): void;
/** Closes any open toolbar popup (font picker, color picker, etc.). */
closePopup(): void;
}

When the editor enters read-only mode, the toolbar automatically hides itself. When read-only mode is disabled, the toolbar reappears.

The toolbar automatically updates button states on every state change:

  • Active (aria-pressed="true") — when isActive() returns true (e.g., bold button when cursor is in bold text)
  • Disabled (aria-disabled="true") — when isEnabled() returns false
  • Popup open — visual indicator when a popup is visible

The toolbar element has:

  • role="toolbar" for screen readers
  • Localized aria-label (defaults to “Formatting options” in English)
  • Individual buttons with aria-pressed and aria-label
  • Tooltip on hover (500ms delay)

Keyboard navigation (roving tabindex):

KeyAction
ArrowRightMove focus to next button
ArrowLeftMove focus to previous button
HomeMove focus to first enabled button
EndMove focus to last enabled button
Enter / SpaceActivate the focused button

When the ”…” overflow button is visible:

  • The button has aria-haspopup="true" and aria-expanded toggled on open/close
  • Localized aria-label (defaults to “More tools” in English)
  • The dropdown menu has role="menu" with role="menuitem" children
  • Group separators use role="separator"

Dropdown keyboard navigation:

KeyAction
ArrowDownMove focus to next menu item
ArrowUpMove focus to previous menu item
Enter / SpaceActivate the focused item
Escape / TabClose dropdown, return focus to overflow button