For an internal review tool, imagine an approved collection notice saying “Collect badges at the foyer desk.” A proposed change says “Collect badges at the loading door.” A reviewer needs to restore that sentence without accidentally changing the approved baseline or saving the left pane as the new version.
Build the two sides with explicit roles
In a browser application whose bundler resolves these CodeMirror packages, mount the view in an existing #notice-merge element:
import { MergeView } from '@codemirror/merge';
import { EditorState } from '@codemirror/state';
import { EditorView, keymap } from '@codemirror/view';
import { history, historyKeymap } from '@codemirror/commands';
import { html } from '@codemirror/lang-html';
const approved = '<p>Collect badges at the foyer desk.</p>';
const proposed = '<p>Collect badges at the loading door.</p>';
const merge = new MergeView({
parent: document.querySelector('#notice-merge'),
a: {
doc: approved,
extensions: [
html(),
EditorState.readOnly.of(true),
EditorView.editable.of(false)
]
},
b: {
doc: proposed,
extensions: [
html(),
history(),
keymap.of(historyKeymap),
EditorView.lineWrapping
]
},
revertControls: 'a-to-b'
});
The HTML language extension supports source editing; it does not render the notice or sanitize it. This is application source for an installed package build, not a script to paste into an otherwise empty local HTML file.
The two read-only settings serve different purposes: the state facet tells extensions that editing is disabled, while the view facet controls browser editing of the content DOM. Neither is an authorization boundary. Your application must still prevent unauthorized replacement or storage of the approved baseline.
Read the direction as a data operation
With this configuration, a is the approved source and b is the proposed destination. The a-to-b control copies the relevant source chunk into b. Reversing that option changes the destination; changing visual orientation does not rename the documents.
Label the panes “Approved baseline” and “Proposed result” in the surrounding interface. Keep a visible explanation of which document the revert button changes. The MergeView implementation follows the chosen direction when generating the replacement transaction.
A revert operates on a changed chunk. It does not understand which sentence was approved, whether a route is safe, or why the change was proposed. Read the resulting source after each acceptance or revert action. Adjacent edits can belong to the same chunk.
Save the right document at the moment of review
After the reviewer has finished:
const reviewedHtml = merge.b.state.doc.toString();
// Pass reviewedHtml and the baseline revision to your save/review service.
Capture b, not the original proposed string and not a. The returned string does not persist itself. Include the appropriate document identity and baseline revision in the application's save contract so a review against an older baseline can be detected.
CodeMirror offers diff and merge interfaces, but this configuration supplies two documents. Resolving concurrent authors' edits against a third shared ancestor requires a separate merge policy. Do not describe every highlighted difference as a conflict.
Check the reviewer action in your actual integration
Use the badge notice fixture to check the workflow. Confirm the approved pane cannot be edited through the interface. Revert the changed chunk from a into b; the proposed pane should now say “foyer desk,” while the approved text remains unchanged. Use Undo in the proposed pane to restore the proposed wording, then make the deliberate final decision again.
Inspect the value captured from merge.b.state.doc, save through the real service, and reopen the reviewed result. Render the final HTML in its intended review environment and read the collection location there. A source diff does not establish the browser's resulting layout or behavior.
The HTML file comparison guide covers reviewing files with existing desktop tools. In an embedded merge interface, keep the approved baseline, editable result, revert direction, and saved revision explicit. Call merge.destroy() when that review view is permanently removed.