# Create and resolve comment threads

> Anchor a DOCX comment to document content, add a reply, and resolve the thread.



Comments are document content. Use the Document API when code needs to create, inspect, update, or delete a thread without driving the built-in comments interface.

This guide creates one anchored thread, adds a reply, and resolves it. The operations work against an open document in the Editor and through supported headless clients.

## Run the complete workflow [#run-the-complete-workflow]

Copy the [tracked-changes fixture](/fixtures/tracked-changes.docx) to your app's public directory as `contract.docx`, then run this browser example:

```ts
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 match = await doc.query.match({
      select: {
        type: 'text',
        pattern: 'Confidential Information',
      },
      require: 'exactlyOne',
    });
    const clause = match.items[0];

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

    const createReceipt = await doc.comments.create(
      {
        target: clause.target,
        text: 'Confirm that this definition matches the current policy.',
      },
      { expectedRevision: match.evaluatedRevision },
    );

    if (!createReceipt.success) {
      throw new Error(`Comment creation failed: ${createReceipt.failure.message}`);
    }

    const afterCreate = await doc.comments.list({ includeResolved: true });
    const replyReceipt = await doc.comments.create(
      {
        parentCommentId: createReceipt.id,
        text: 'Confirmed against the policy dated July 2026.',
      },
      { expectedRevision: afterCreate.evaluatedRevision },
    );

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

    const afterReply = await doc.comments.list({ includeResolved: true });
    const resolveReceipt = await doc.comments.patch(
      {
        commentId: createReceipt.id,
        status: 'resolved',
      },
      { expectedRevision: afterReply.evaluatedRevision },
    );

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

    console.log('Resolved comment:', createReceipt.id);
  },
});

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

```

The example deliberately re-lists comments between mutations. Each mutation advances the document revision, so the next operation uses a current `expectedRevision`.

## Anchor the root comment [#anchor-the-root-comment]

A root comment needs text and a document target. A text query returns a `SelectionTarget` that can be passed directly to `comments.create()`.

Do not derive the target from the rendered DOM or from `highlightRange`. DOM positions belong to layout. `highlightRange` describes the displayed snippet. The query target addresses document content.

On success, the creation receipt includes the new thread ID. Keep that ID for replies and later lifecycle changes.

## Add replies without another target [#add-replies-without-another-target]

A reply belongs to an existing thread. Pass `parentCommentId` and text. Do not pass the root target again.

The reply is another document mutation. Inspect its receipt before resolving the thread or saving the file.

## Resolve or reopen the thread [#resolve-or-reopen-the-thread]

`comments.patch()` changes exactly one comment field per call. Set `status: 'resolved'` to resolve the root thread. Set `status: 'active'` in a later call to reopen it.

List with `includeResolved: true` when the application needs to show both states. A resolved thread remains in the DOCX unless it is explicitly deleted.

Use [comments in the built-in UI](/editor/built-in-ui/comments) for the standard human workflow. Use [a custom comments UI](/editor/custom-ui/comments) when your application owns the thread list and navigation.
