Compare two DOCX documents in the browser using the Diffing extension commands. The differences are replayed onto the visible editor as tracked changes.
Quick start
The core flow is three steps: parse the second document with a headless editor, compare, and replay.
// 1. Parse the second document headlessly
const [docx, media, mediaFiles, fonts] = await Editor.loadXmlData(targetFile);
const headless = new Editor({
isHeadless: true,
skipViewCreation: true,
extensions: getStarterExtensions(),
content: docx,
mode: 'docx',
media,
mediaFiles,
fonts,
});
// 2. Compare the visible editor against the headless document
const diff = editor.commands.compareDocuments(
headless.state.doc,
headless.converter?.comments ?? [],
headless.converter?.translatedLinkedStyles ?? null,
headless.converter?.translatedNumbering ?? null,
);
// 3. Replay the differences as tracked changes
editor.commands.replayDifferences(diff, { applyTrackedChanges: true });
headless.destroy();
After replay, the editor shows insertions, deletions, and formatting changes as tracked changes. Users can review them with the standard accept/reject workflow.
Headless editor pattern
The second document needs to be parsed into a ProseMirror document tree before comparison. Create a headless Editor instance — no DOM, no view — just the parsed document state.
const headless = new Editor({
isHeadless: true,
skipViewCreation: true,
extensions: getStarterExtensions(),
content: docx,
mode: 'docx',
media,
mediaFiles,
fonts,
});
Extract what you need from headless.state.doc, headless.converter.comments, headless.converter.translatedLinkedStyles, and headless.converter.translatedNumbering. Then call headless.destroy().
Bidirectional comparison
To show changes on both sides (like the diffing example), run the comparison in both directions:
// Left editor shows what Right changed
const leftDiff = leftEditor.commands.compareDocuments(
rightHeadless.state.doc,
rightHeadless.converter?.comments ?? [],
rightHeadless.converter?.translatedLinkedStyles ?? null,
rightHeadless.converter?.translatedNumbering ?? null,
);
leftEditor.commands.replayDifferences(leftDiff, { applyTrackedChanges: true });
// Right editor shows what Left changed
const rightDiff = rightEditor.commands.compareDocuments(
leftHeadless.state.doc,
leftHeadless.converter?.comments ?? [],
leftHeadless.converter?.translatedLinkedStyles ?? null,
leftHeadless.converter?.translatedNumbering ?? null,
);
rightEditor.commands.replayDifferences(rightDiff, { applyTrackedChanges: true });
Tracked changes vs silent apply
By default, replayDifferences wraps every change in tracked-change marks. Set applyTrackedChanges: false to apply changes silently — useful when you want to merge documents without review.
// Apply silently (no tracked changes)
editor.commands.replayDifferences(diff, { applyTrackedChanges: false });
Tracked changes require a user on the SuperDoc or Editor instance. Without one, changes are applied silently regardless of the option.
API reference
See the Diffing extension page for the full command signatures and DiffResult type.