EngineeringMarch 12, 2026·2 min read

Track Changes in a React DOCX Editor

How to enable track changes in a React DOCX editor and automate document review with AI agents using DocxReviewer.

Why track changes matters

Track changes records every insertion, deletion, and formatting change — attributed to an author with a timestamp. Legal teams use it for redlining. Compliance teams use it for audit trails. Editorial teams use it for review.

Suggesting mode

Set mode="suggesting" and the editor tracks every edit automatically:

import { DocxEditor } from "@eigenpal/docx-js-editor";
 
function ContractEditor({ buffer }: { buffer: ArrayBuffer }) {
  return (
    <DocxEditor
      documentBuffer={buffer}
      mode="suggesting"
      author="Current User"
    />
  );
}
  • Insertions get a green underline
  • Deletions get a red strikethrough
  • Consecutive edits by the same author are grouped into a single revision

Switch between "editing" (direct edits), "suggesting" (tracked changes), and "viewing" (read-only) at any time.

Accepting and rejecting

The editor exposes acceptChange(from, to) and rejectChange(from, to) commands:

  • Accept — insertion stays, deletion is removed
  • Reject — insertion is removed, deletion stays

The sidebar shows accept/reject buttons on each tracked change card.

Round-trip fidelity

Documents redlined in Word open in the editor with all revisions intact, and vice versa. All revision metadata (author, date, IDs) is preserved on save.

Try it

Automating track changes with AI agents

Manual redlining doesn't scale. @eigenpal/docx-editor-agents provides DocxReviewer — a headless API for programmatic document review. No DOM, runs anywhere.

npm install @eigenpal/docx-editor-agents

Basic usage

import { DocxReviewer } from "@eigenpal/docx-editor-agents";
 
const reviewer = await DocxReviewer.fromBuffer(buffer, "AI Reviewer");
 
// Read as plain text (LLM-friendly format)
const text = reviewer.getContentAsText();
// [0] (h1) Service Agreement
// [1] The liability cap is $50k per incident.
 
// Comment
reviewer.addComment(1, "This cap seems too low.");
 
// Replace (creates a tracked change)
reviewer.replace(1, "$50k", "$500k");
 
// Export
const output = await reviewer.toBuffer();

The output is a standard DOCX with tracked changes and comments — opens in Word, Google Docs, or the editor above.

With an LLM

Read the document, send to any model, apply the response as tracked changes:

import { DocxReviewer } from "@eigenpal/docx-editor-agents";
import Anthropic from "@anthropic-ai/sdk";
 
const client = new Anthropic();
const reviewer = await DocxReviewer.fromBuffer(buffer, "Claude Reviewer");
 
const response = await client.messages.create({
  model: "claude-sonnet-4-20250514",
  max_tokens: 4096,
  messages: [{
    role: "user",
    content: `Review this contract. Return JSON with "comments" and "replacements":
${reviewer.getContentAsText()}`
  }],
});
 
const actions = JSON.parse(response.content[0].text);
reviewer.applyReview({
  comments: actions.comments,
  proposals: actions.replacements,
});
 
const output = await reviewer.toBuffer();

applyReview is fault-tolerant — individual failures are collected in result.errors instead of throwing, so one bad paragraph index doesn't break the review.

Why this works for agents

  • Headless — no DOM, runs on servers and edge functions
  • LLM-nativegetContentAsText() returns [index] text format, no JSON escaping issues
  • Robust matching — handles smart quotes, whitespace variations, LLM truncation
  • Batch operations — single applyReview() call for the full review
  • Word-compatible output — proper revision marks, comments, and metadata

Full DocxReviewer API reference

Next steps