Imagine a maintenance note that ends with a horizontal rule. Its author needs to add “Record the replacement date” below that rule, but clicking the whitespace does not place a normal text cursor there. A gap selection can expose that location without forcing the application to store a permanent blank paragraph after every block.
Install the selection plugin and its styling
For an existing ProseMirror application with a working schema and editing keymaps:
import { gapCursor } from 'prosemirror-gapcursor';
import 'prosemirror-gapcursor/style/gapcursor.css';
const gapSelectionPlugin = gapCursor();
Add gapSelectionPlugin once to the plugins array used to create the editor state. The stylesheet import assumes a bundler that handles CSS; otherwise load the package's styles through the application's normal stylesheet pipeline. Preserve the existing state, view, commands, and document-loading setup.
The plugin handles suitable clicks and arrow-key movement around locations without an ordinary text selection. It draws the selection with the ProseMirror-gapcursor class. If the selection exists in state but nothing appears, inspect that class and its styles before changing the document.
The gap cursor is different from selecting the horizontal rule itself. A node selection targets an existing node. A gap selection identifies a position between nodes where the application can offer a supported editing action.
Check the schema before adding empty paragraphs
The default behavior allows gaps beside leaf blocks and isolating nodes where the surrounding content rules allow an appropriate textblock. A plain paragraph must actually be available in the relevant position. Required attributes or a restricted parent can change that result.
The schema's node specs can set allowGapCursor: true or false to customize whether gaps are allowed inside that node. Use that option for a defined authoring need rather than enabling it everywhere to hide an unexplained selection problem. The schema guide explains parent content expressions and default filler nodes.
For the maintenance note, inspect the actual structure at the document end. A visual divider rendered by CSS is different from a leaf block such as horizontal_rule. Confirm the node type and position in the editor model, not just the appearance of the page.
Observe the selection without changing it
During development, inspect the current editor state after clicking beside the final rule:
import { GapCursor } from 'prosemirror-gapcursor';
const selection = view.state.selection;
const isGapSelection = selection instanceof GapCursor;
const selectedPosition = selection.head;
Here view is the current EditorView. These reads do not insert a paragraph. Use the application's actual typing and keymap integration to add the replacement-date sentence, then inspect the resulting document. The gap selection relies on that existing input setup to complete the edit.
Test both mouse and keyboard access in the editor you ship. Also try a block at the beginning, two adjacent leaf blocks, and a restricted container only if those structures exist in the application's schema. A location that remains unavailable may be correctly excluded by the document grammar.
Save the sentence, not the cursor's appearance
Export or persist the resulting document through the application's supported model path. The gap selection's visible stripe is an editor cue. The saved maintenance note needs the actual paragraph containing the replacement-date instruction.
The decoration guide explains the related distinction between view-only presentation and saved content. Reopen the note and verify that the new sentence sits after the divider. It should remain readable even when the editor has no active selection.