Skip to content

Quick insert ​

ElementQuickInsert opens a menu with a search field and the elements that can be inserted at a position. Type to filter, press Enter to insert the first match, or use the arrow keys to pick one.

ts
import { ElementQuickInsert } from 'ckeditor5-elements';
import 'ckeditor5-elements/index.css';

The menu is shown by the ElementMenu plugin, which ElementQuickInsert loads. It does not add a right-click menu; that needs ElementContextMenu.

Which elements are listed ​

Only the elements that the schema allows at exactly the position. Nothing is split to make room: inside a paragraph, only inline elements (such as a line break) are allowed, so headings are not listed there. Between blocks, the blocks are.

Generic schema items (such as $text) are never listed. The elements are listed in the order they were registered.

Keyboard ​

Alt+Enter (Option+Enter on macOS) opens the menu at the cursor. The keystroke is listed in the accessibility help (Alt+0):

Source
ts
import { Essentials, Heading, Paragraph, SourceEditing } from 'ckeditor5';
import { ElementQuickInsert } from 'ckeditor5-elements';
import type { Demo } from './shared/demo';

export default {
	config: {
		plugins: [Essentials, SourceEditing, Paragraph, Heading, ElementQuickInsert],
		toolbar: ['undo', 'redo', 'sourceEditing', '|', 'heading'],
		// Elements without a label are listed by their model name.
		elementQuickInsert: { labels: { softBreak: 'Line break' } }
	},
	data:
		'<p>Put the cursor in the middle of this sentence and press Alt+Enter (Option+Enter on macOS). ' +
		'Inside a paragraph, only inline elements are allowed, so the menu offers a line break.</p>'
} satisfies Demo;

Before or after a block ​

To insert blocks, open the menu for the position before or after a block. The quickInsertBefore and quickInsertAfter commands do that for the block with the cursor, or for a given element. Use them as toolbar buttons or as context menu items:

Source
ts
import { Essentials, Heading, Paragraph, Plugin, SourceEditing } from 'ckeditor5';
import { ElementContextMenu, ElementOrPositionButtonView, insertIcon, ElementQuickInsert } from 'ckeditor5-elements';
import { Note } from 'ckeditor5-elements-example';
import type { Demo } from './shared/demo';

/**
 * Toolbar buttons for the `quickInsertBefore` and `quickInsertAfter` commands: they open the quick insert menu before
 * or after the block with the cursor.
 */
class InsertButtons extends Plugin {
	public static get requires(): readonly [typeof ElementQuickInsert] {
		return [ElementQuickInsert] as const;
	}

	public init(): void {
		const editor = this.editor;

		for (const name of ['quickInsertBefore', 'quickInsertAfter'] as const) {
			const command = editor.commands.get(name);

			if (command) {
				editor.ui.componentFactory.add(
					name,
					locale => new ElementOrPositionButtonView(locale, command, { withText: true })
				);
			}
		}
	}
}

export default {
	config: {
		plugins: [Essentials, SourceEditing, Paragraph, Heading, Note, ElementContextMenu, InsertButtons],
		toolbar: ['undo', 'redo', 'sourceEditing', '|', 'heading', '|', 'quickInsertBefore', 'quickInsertAfter'],
		// The same commands in the context menu.
		elementContextMenu: (element, editor) => [
			{
				title: 'Insert',
				icon: insertIcon,
				items: [editor.commands.get('quickInsertBefore'), editor.commands.get('quickInsertAfter')]
			}
		],
		elementQuickInsert: {
			labels: { paragraph: 'Paragraph', heading1: 'Heading 1', heading2: 'Heading 2', note: 'Note' },
			exclude: ['heading3']
		}
	},
	data:
		'<h2>Insert next to a block</h2>' +
		'<p>Put the cursor here and click <b>Insert after</b>, or right-click and choose <b>Insert › Insert after</b>.</p>' +
		'<aside class="note"><p>Inside a note, blocks can be inserted next to this paragraph too.</p></aside>'
} satisfies Demo;

They are enabled only when something can be inserted at that position.

From code ​

The quickInsert command inserts an element by its name. It takes the target first, like all element commands: a position, an element (meaning the position before it), or nothing (the selection). The plugin opens the menu, with open().

ts
// Inserts a heading at the position.
editor.execute('quickInsert', position, 'heading2');

// Opens the menu for the position before the element.
editor.plugins.get('ElementQuickInsert').open(element);

After inserting, an object is selected; an element that holds text gets the cursor inside it; an element that holds blocks gets a paragraph with the cursor.

Source
ts
import { Essentials, Heading, Paragraph, SourceEditing, type ClassicEditor } from 'ckeditor5';
import { ElementQuickInsert } from 'ckeditor5-elements';
import type { Demo } from './shared/demo';

/**
 * Buttons outside the editor: one executes the `quickInsert` command, one opens the menu of the plugin.
 */
function addControls(editor: ClassicEditor, container: HTMLElement): void {
	const root = editor.model.document.getRoot();
	const controls = document.createElement('div');

	const actions: [label: string, run: () => void][] = [
		// With an element name: inserts it. The target comes first: here, the position at the end of the root.
		[
			'Insert a heading at the end',
			() => {
				if (root) {
					editor.execute('quickInsert', editor.model.createPositionAt(root, 'end'), 'heading2');
				}
			}
		],
		// The menu, of the plugin. An element as the target means the position before it.
		[
			'Open the menu before the first block',
			() => {
				const first = root?.getChild(0);

				if (first?.is('element')) {
					editor.plugins.get(ElementQuickInsert).open(first);
				}
			}
		]
	];

	controls.className = 'editor-demo__controls';

	for (const [label, run] of actions) {
		const button = document.createElement('button');

		button.textContent = label;
		button.addEventListener('click', run);
		controls.append(button);
	}

	container.append(controls);
}

export default {
	config: {
		plugins: [Essentials, SourceEditing, Paragraph, Heading, ElementQuickInsert],
		toolbar: ['undo', 'redo', 'sourceEditing', '|', 'heading'],
		elementQuickInsert: { labels: { paragraph: 'Paragraph', heading1: 'Heading 1', heading2: 'Heading 2' } }
	},
	data: '<p>The first block.</p><p>The last block.</p>',
	ready: addControls
} satisfies Demo;

open(target?, domTarget?) shows the menu next to the DOM target, by default next to the element or the selection. editor.plugins.get('ElementQuickInsert') also has getItems(target?), and hasItems(target?).

Configuration ​

ts
elementQuickInsert: {
	// Labels by model name. Elements without a label are listed by their model name.
	labels: { paragraph: 'Paragraph', heading1: 'Heading 1' },

	// Elements that are never listed.
	exclude: ['heading3'],

	// The keystroke that opens the menu at the cursor. `false`: none.
	keystroke: 'Alt+Enter'
}

Limitations ​

  • The menu closes when the document changes while it is open (e.g. by another user), so it never inserts at an outdated position.
  • Elements are inserted empty, so elements that need attributes to be useful (e.g. an image needs its source) should be excluded.