Tracked changes
Enable suggesting mode to record edits as Word tracked changes. Text, formatting, and structural revisions you can accept or reject in the UI or via API.
In suggesting mode every edit becomes a revision instead of a direct change. Insertions render underlined, deletions render struck through, and each revision carries its author and timestamp. Revisions serialize to Word's native <w:ins> / <w:del> markup, so a document reviewed in the editor and a document reviewed in Word are interchangeable.
Enable suggesting mode
Set mode="suggesting". Pair with onModeChange if you want to own the mode state; without it the editor manages mode internally (users can switch via the mode picker in the toolbar).
import { useState } from 'react';
import { DocxEditor, type EditorMode } from '@eigenpal/docx-editor-react';
export function ReviewerEditor({ buf, reviewer }: { buf: ArrayBuffer; reviewer: string }) {
const [mode, setMode] = useState<EditorMode>('suggesting');
return (
<DocxEditor
documentBuffer={buf}
author={reviewer}
mode={mode}
onModeChange={setMode}
/>
);
}EditorMode is "editing" | "suggesting" | "viewing". Lock reviewers into suggesting by passing mode="suggesting" and ignoring mode changes, or hide the toolbar and provide your own switch.
What gets tracked
The revision model covers more than inline text:
- Text insertions and deletions, including replacements (shown as "Replaced X with Y").
- Paragraph structure: inserted and deleted paragraph breaks, paragraph property changes.
- Tables: row and cell insert, delete, and merge, plus row, cell, and table property changes.
- Images: inserted and deleted images.
- Lists: numbering changes. Rejecting a list change reverts both the text and the numbering.
All of these round-trip through DOCX as real OOXML revisions, not editor-private state.
The review sidebar
Each revision appears as a card in the sidebar next to the document, labeled with what changed ("Added", "Deleted", "Inserted row", "Changed paragraph properties", and so on), who made it, and when. Each card has Accept and Reject buttons, and a reply box that attaches a comment to the revision. Placing the cursor inside a change opens the sidebar and expands the matching card.
Documents that already contain revisions made in Word show them the same way; accepting or rejecting works regardless of which tool recorded the change.
Author and date attribution
The author prop names the person behind new revisions (and new comments). Word shows the same name in its Review pane.
<DocxEditor documentBuffer={buf} author="Jess Lin" mode="suggesting" />Each revision records a timestamp at creation. Both fields survive save and reload.
Accept and reject via API
The accept/reject operations behind the sidebar buttons are exported as ProseMirror commands from @eigenpal/docx-editor-core/prosemirror/commands:
| Command | Effect |
|---|---|
acceptChangeById(revisionId) | Accept one revision by id |
rejectChangeById(revisionId) | Reject one revision by id |
acceptAllChanges() | Accept every revision, all revision types |
rejectAllChanges() | Reject every revision, all revision types |
Each returns a Command you run against the editor's view. Capture the view with the onEditorViewReady prop:
import { useRef } from 'react';
import type { EditorView } from 'prosemirror-view';
import { DocxEditor } from '@eigenpal/docx-editor-react';
import { acceptAllChanges } from '@eigenpal/docx-editor-core/prosemirror/commands';
export function BulkReview({ buf }: { buf: ArrayBuffer }) {
const viewRef = useRef<EditorView | null>(null);
return (
<>
<button
onClick={() => {
const view = viewRef.current;
if (view) acceptAllChanges()(view.state, view.dispatch);
}}
>
Accept all
</button>
<DocxEditor documentBuffer={buf} onEditorViewReady={(v) => (viewRef.current = v)} />
</>
);
}To enumerate revisions (for your own list UI or an approval workflow), use extractTrackedChanges from @eigenpal/docx-editor-core/prosemirror/utils/extractTrackedChanges. It takes the editor state and returns the revision entries plus a comment-to-revision map.
Propose a change programmatically
DocxEditorRef.proposeChange inserts a tracked replacement without the user typing, anchored to a paragraph by its w14:paraId:
ref.current?.proposeChange({
paraId: 'ABC12300',
search: 'thirty (30) days',
replaceWith: 'sixty (60) days',
author: 'Contract Bot',
});It returns false when the paragraph or search text is not found. This is the primitive AI redlining builds on; see AI redlining for driving it from an LLM.
Interop with Word
- Saving in suggesting mode writes standard
<w:ins>and<w:del>elements. Word lists them in its Review pane with the same author and date, and Word's Accept/Reject resolves them. - Opening a document that contains Word revisions renders them inline and in the sidebar. Nothing is flattened on load.
- Accept-all and reject-all resolve every revision type, including structural table and list revisions.
Next steps
- AI redlining for LLM-proposed tracked changes
- Comments for discussion threads alongside revisions
- Props reference for
mode,author, andonModeChange
Loading & saving
Load DOCX files into the editor from a File, ArrayBuffer, or URL, then save them back with selective OOXML repack, autosave, and read-only rendering.
Comments
Add comment threads to DOCX documents: replies, resolve state, the comments sidebar, controlled comment props and callbacks, and programmatic APIs.