Skip to content

Toolbar Configuration

The notectl toolbar is fully declarative. You configure it by passing a toolbar option to createEditor() — an array of plugin groups that maps directly to the visual layout.

Toolbar close-up

The toolbar option is an array of arrays. Each inner array represents a visual group of toolbar buttons, with separators rendered between groups:

import {
createEditor,
TextFormattingPlugin,
HeadingPlugin,
ListPlugin,
} from '@notectl/core';
const editor = await createEditor({
toolbar: [
[new TextFormattingPlugin()], // Group 1: B, I, U
[new HeadingPlugin()], // Group 2: Heading dropdown
[new ListPlugin()], // Group 3: List buttons
],
});

The order of groups and plugins within groups determines their visual order in the toolbar.

When you provide a toolbar config:

  1. A ToolbarPlugin is automatically created with the group layout
  2. Each plugin in the toolbar arrays is registered with the editor
  3. Plugins register their toolbar items during init()
  4. The ToolbarPlugin renders buttons in the order defined by your groups

If you don’t need a toolbar (headless mode), use the plugins array directly:

const editor = await createEditor({
plugins: [
new TextFormattingPlugin(),
new HeadingPlugin(),
new ListPlugin(),
],
});

In this mode, no toolbar UI is rendered. You control formatting through the command API:

editor.executeCommand('toggleBold');
editor.executeCommand('setHeading1');

You can use toolbar for visible plugins and plugins for background plugins that don’t need toolbar UI:

const editor = await createEditor({
toolbar: [
[new TextFormattingPlugin()],
[new HeadingPlugin()],
],
plugins: [
myCustomMiddlewarePlugin,
myAnalyticsPlugin,
],
});

Here’s a complete toolbar setup with all built-in plugins organized into logical groups:

import {
createEditor,
TextFormattingPlugin,
HeadingPlugin,
BlockquotePlugin,
LinkPlugin,
ListPlugin,
TablePlugin,
CodeBlockPlugin,
HorizontalRulePlugin,
StrikethroughPlugin,
SuperSubPlugin,
HighlightPlugin,
TextColorPlugin,
AlignmentPlugin,
FontPlugin,
FontSizePlugin,
ImagePlugin,
HardBreakPlugin,
} from '@notectl/core';
import { STARTER_FONTS } from '@notectl/core/fonts';
const editor = await createEditor({
toolbar: [
// Text formatting: Bold, Italic, Underline
[new TextFormattingPlugin({ bold: true, italic: true, underline: true })],
// Block types: Paragraph / Heading selector
[new HeadingPlugin()],
// Block elements
[new BlockquotePlugin(), new LinkPlugin()],
// Lists: Ordered and Unordered
[new ListPlugin()],
// Tables and Images
[new TablePlugin(), new ImagePlugin()],
// Code blocks
[new CodeBlockPlugin()],
// Additional inline formatting
[
new HorizontalRulePlugin(),
new StrikethroughPlugin(),
new SuperSubPlugin(),
new HighlightPlugin(),
new TextColorPlugin(),
],
// Typography: Alignment, Font, Size
[
new AlignmentPlugin(),
new FontPlugin({ fonts: [...STARTER_FONTS] }),
new FontSizePlugin({ sizes: [12, 16, 24, 32, 48], defaultSize: 16 }),
],
],
plugins: [new HardBreakPlugin()], // No toolbar UI needed
placeholder: 'Start typing...',
autofocus: true,
});

When the viewport is too narrow to display all toolbar items, notectl can handle the overflow automatically. Three modes are available via ToolbarOverflowBehavior:

Items that don’t fit are hidden behind a ”…” dropdown button. The overflow controller measures available width using a ResizeObserver and redistributes items dynamically.

Toolbar with overflow burger button

Click the ”…” button to reveal the hidden items in a dropdown menu:

Toolbar overflow dropdown open

import { createEditor, ToolbarOverflowBehavior } from '@notectl/core';
const editor = await createEditor({
toolbar: {
groups: [
[new TextFormattingPlugin()],
[new HeadingPlugin()],
[new ListPlugin()],
],
overflow: ToolbarOverflowBehavior.BurgerMenu, // default
},
});

The toolbar wraps to multiple rows when items overflow. This is a pure CSS solution — no JavaScript measurement is needed.

Toolbar with flow overflow wrapping to multiple rows

const editor = await createEditor({
toolbar: {
groups: [
[new TextFormattingPlugin()],
[new HeadingPlugin()],
[new ListPlugin()],
],
overflow: ToolbarOverflowBehavior.Flow,
},
});

No responsive behavior. Items that exceed the container width are clipped. Use this when you control the layout externally or know the toolbar will always fit.

const editor = await createEditor({
toolbar: {
groups: [[new TextFormattingPlugin()]],
overflow: ToolbarOverflowBehavior.None,
},
});

Each plugin has a priority number that determines its rendering order within a toolbar group. Lower numbers render first. You generally don’t need to worry about this — the defaults produce a natural ordering.

PluginDefault Priority
HardBreakPlugin10
TextFormattingPlugin20
FontSizePlugin21
FontPlugin22
StrikethroughPlugin22
SuperSubPlugin23
TextColorPlugin23
HighlightPlugin24
LinkPlugin25
HeadingPlugin30
BlockquotePlugin35
ListPlugin35
CodeBlockPlugin36
HorizontalRulePlugin40
TablePlugin40
ImagePlugin45
AlignmentPlugin90