Skip to content

Selection

Selection provides commands for programmatic selection (setSelection, selectNode, selectParentNode, extendSelection) and storage helpers for reading the current selection state (getText, getNode, isEmpty, getRange, getCursor). All storage functions read directly from the current editor state, always returning up-to-date values.

Not included in StarterKit. Add it separately.

import { Editor, Document, Paragraph, Text, Selection } from '@domternal/core';
import '@domternal/theme';
const editor = new Editor({
element: document.getElementById('editor')!,
extensions: [Document, Paragraph, Text, Selection],
content: '<p>Select some text in this editor.</p>',
});
// Read selected text
editor.on('selectionUpdate', () => {
const text = editor.storage.selection.getText();
if (text) console.log('Selected:', text);
});

Selection has no configurable options.

Creates a text selection between two positions. If only from is provided, creates a collapsed cursor at that position. Returns false if the positions are out of bounds.

// Range selection
editor.commands.setSelection(5, 10);
// Collapsed cursor
editor.commands.setSelection(5);
// With chaining
editor.chain().focus().setSelection(5, 10).run();

Creates a node selection at the given position. The position must point to the start of a node. Returns false if the position is out of bounds or no node exists there.

editor.commands.selectNode(0); // select the first node

Selects the nearest parent node of the current selection that is selectable (selectable !== false in the node spec). Walks up the document tree from the current depth. Returns false if no selectable parent is found.

editor.commands.selectParentNode();

Extends the current selection in the given direction. Does not collapse the selection, only moves one edge.

editor.commands.extendSelection('left'); // extend from edge one position left
editor.commands.extendSelection('right'); // extend to edge one position right
editor.commands.extendSelection('start'); // extend from edge to document start
editor.commands.extendSelection('end'); // extend to edge to document end
DirectionBehavior
leftMoves from one position left (clamped to document start)
rightMoves to one position right (clamped to document end)
startMoves from to the start of the document
endMoves to to the end of the document

The start and end directions use Selection.atStart() and Selection.atEnd() from ProseMirror to find the first/last valid text position, handling nested structures correctly.

Access selection helpers via editor.storage.selection:

MethodReturnsDescription
getText()stringSelected text content. Uses doc.textBetween(from, to, ' ') with space as block separator.
getNode()PMNode | nullThe selected node if it’s a NodeSelection, otherwise null.
isEmpty()booleantrue if the selection is collapsed (cursor, no range).
getRange(){ from: number; to: number }Current selection positions.
getCursor()number | nullCursor position if collapsed, null if range selection.
const { getText, getNode, isEmpty, getRange, getCursor } = editor.storage.selection;
console.log(getText()); // "selected text"
console.log(getNode()); // null (or PMNode for node selections)
console.log(isEmpty()); // false
console.log(getRange()); // { from: 5, to: 18 }
console.log(getCursor()); // null (range selection)

All storage functions read directly from editor.state on each call, so they always return the current value without caching.

Selection does not register any keyboard shortcuts.

Selection does not register any input rules.

Selection does not register any toolbar items.

The storage functions are initialized in the onCreate hook. Each function reads from editor.state when called:

  • getText(): calls doc.textBetween(from, to, ' ') with a space separator between blocks
  • getNode(): checks if the selection is a NodeSelection and returns selection.node
  • isEmpty(): returns state.selection.empty
  • getRange(): returns { from: state.selection.from, to: state.selection.to }
  • getCursor(): returns selection.from only if the selection is empty, otherwise null

All commands use tr.doc and tr.selection instead of state.doc and state.selection. This ensures correct behavior when commands are chained, since prior commands in the chain may have modified the document (changing positions and document size).

setSelection validates that positions are within [0, tr.doc.content.size]. selectNode validates that the position is within bounds and that a node exists at that position. Both return false for invalid positions without throwing.

The left and right directions clamp to the document boundaries using Selection.atStart(doc).from and Selection.atEnd(doc).to, which find the first and last valid text positions. This handles nested structures (like doc > blockquote > paragraph) where position 0 or doc.content.size may not be a valid text position.

import { Selection } from '@domternal/core';
import type { SelectionOptions, SelectionStorage } from '@domternal/core';
ExportTypeDescription
SelectionExtensionThe selection extension
SelectionOptionsTypeScript typeOptions for Selection.configure() (empty)
SelectionStorageTypeScript typeShape of editor.storage.selection

@domternal/core - Selection.ts