An HTML authoring tool has an “Insert safety section” button. Clicking it should add one complete section, and one Undo should remove that section without also removing the sentence the author typed just before it. A generic time delay between edits is a poor way to define that boundary.
Install history once in the editor's state
For an existing application assembling its own CodeMirror setup:
import { EditorView, keymap } from '@codemirror/view';
import {
history, historyKeymap, isolateHistory, undo, redo
} from '@codemirror/commands';
const view = new EditorView({
parent: document.querySelector('#source'),
doc: '<h1>Workshop</h1>\n',
extensions: [history(), keymap.of(historyKeymap)]
});
Keep your application's other editing, language, and visual extensions. If it already uses a setup that installs history and its keymap, inspect that setup before adding another copy. The example shows the history dependencies explicitly; it is not a complete production editor configuration.
An Undo button can call undo(view) and Redo can call redo(view). Use type="button" on those controls when the editor sits inside a form. A command returning false means there was no corresponding history action to apply; it is not a save failure.
Give the insertion a clear boundary
With view referring to the current editor, insert the original sample section as one transaction:
function insertSafetySection() {
const at = view.state.selection.main.head;
view.dispatch({
changes: {
from: at,
insert: '\n<section><h2>Safety</h2><p>Check the guard.</p></section>\n'
},
annotations: isolateHistory.of('full')
});
}
This deliberately inserts at the primary cursor and leaves any selection's text intact. A tool that promises to replace a selection needs from and to from that selection instead. Resolve that behavior before attaching the button.
The annotation prevents this transaction from joining history events on either side. The API also offers before and after for a one-sided boundary. Isolation does not mean a document is immutable, and it does not turn the section into a separately stored record. History implementation
Decide which background updates belong in Undo
An application can annotate a transaction with Transaction.addToHistory.of(false) from @codemirror/state to exclude it from recorded undo events. That is useful only when the application has a reason to keep that change outside the author's undo actions. It is not a general repair for confusing undo grouping.
Excluded changes still alter the current document, and the history machinery must map existing events through them. If you are loading an unrelated document, consider its own state and history lifecycle instead of replacing the entire text and expecting the previous document's Undo stack to become appropriate.
Reconfiguring a language through a CodeMirror compartment can preserve the current editor state. Replacing that state entirely is a different operation and requires an explicit policy for retained history.
Check the author's expected sequence
Type a short sentence, insert the safety section, then press Undo once. The inserted section should disappear while the earlier sentence remains. Redo should restore the exact section. Read the document value after each action, rather than counting toolbar clicks alone.
Finally save the intended current value and reopen it through the application. A normal saved HTML string contains the document, not its entire editor history. Persisting history across sessions requires an explicit compatible state-serialization design; do not promise it from a successful Undo in the open tab.