Replace and delete content

Use fresh query targets to change an open DOCX and inspect each mutation receipt.

Use replace() and delete() after a query has identified the exact content to change. Both operations accept a target from query.match() and return a receipt that says whether the mutation succeeded.

This guide uses the tracked-changes fixture. Serve it from /contract.docx in your app, or update the document URL in the example.

1. Run two targeted mutations

Wait for the editor, replace one company name, then run a fresh query before deleting a sentence:

import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

const superdoc = new SuperDoc({
  selector: '#editor',
  document: '/contract.docx',
  onReady: async ({ superdoc }) => {
    const doc = superdoc.activeEditor?.doc;
    if (!doc) throw new Error('The active document is unavailable.');

    const companyMatch = await doc.query.match({
      select: { type: 'text', pattern: 'Amazing' },
      require: 'exactlyOne',
    });
    const company = companyMatch.items[0];

    if (!company || company.matchKind !== 'text') {
      throw new Error('The company name was not found.');
    }

    const replaceReceipt = await doc.replace(
      {
        target: company.target,
        text: 'Northstar',
      },
      {
        changeMode: 'direct',
        expectedRevision: companyMatch.evaluatedRevision,
      },
    );

    if (!replaceReceipt.success) {
      throw new Error(`Replace failed: ${replaceReceipt.failure?.message ?? 'Unknown error'}`);
    }

    console.log('Replace receipt:', replaceReceipt);

    const liabilityMatch = await doc.query.match({
      select: {
        type: 'text',
        pattern: 'The total liability under this section shall not exceed $500,000.',
      },
      require: 'exactlyOne',
    });
    const liability = liabilityMatch.items[0];

    if (!liability || liability.matchKind !== 'text') {
      throw new Error('The liability sentence was not found.');
    }

    const deleteReceipt = await doc.delete(
      {
        target: liability.target,
        behavior: 'exact',
      },
      {
        changeMode: 'direct',
        expectedRevision: liabilityMatch.evaluatedRevision,
      },
    );

    if (!deleteReceipt.success) {
      throw new Error(`Delete failed: ${deleteReceipt.failure.message}`);
    }

    console.log('Delete receipt:', deleteReceipt);
  },
});

window.addEventListener('beforeunload', () => {
  superdoc.destroy();
});

The displayed source is typechecked against the public v2 browser API.

2. Re-query after a mutation

The replacement advances the document revision. The example runs a new query before deleting instead of reusing an earlier target.

expectedRevision makes each operation reject stale query input. changeMode: 'direct' applies the change immediately. Use 'tracked' when a change should remain a suggestion for human review.

behavior: 'exact' removes only the resolved text range. The default 'selection' behavior may expand to block edges when the query covers an entire boundary block.

3. Inspect receipts before continuing

Check success before saving, exporting, or starting another dependent operation. A failed receipt includes a stable failure code and message. A successful receipt includes the resolved target, and may include revision and effect details depending on the operation.

Common failures at this stage mean the target is stale, the text no longer matches, or the current editor mode does not allow the mutation. Re-query current document state before retrying. Do not guess offsets or silently ignore the receipt.

Next, learn how to handle receipts and errors without unsafe retry loops. For several edits that must succeed together, use a revision-guarded mutation plan instead of chaining independent calls. The generated replace reference and delete reference list the full input and receipt shapes.

On this page