Skip to content
ComPDF
DemoAPI ReferenceFAQ
New Release

Open-Source PDF SDK & AI Document Processing

Get the full self-hosted SDK and AI document processing on GitHub. One-click deploy to quickly build your document workflows.

Guides

Annotation Replies

ComPDF React Native SDK provides annotation reply APIs for adding, reading, updating, and removing replies on PDF annotations. You can also set mark states and review states on annotations or annotation replies. These APIs are useful for document review, collaborative annotation workflows, feedback tracking, and approval flows.

API Overview

Annotation reply APIs are available on CPDFDocument:

ts
addAnnotationReply(
  annotation: CPDFAnnotation,
  options: { content: string; title?: string }
): Promise<CPDFReplyAnnotation | null>;

getAnnotationReplies(
  annotation: CPDFAnnotation
): Promise<CPDFReplyAnnotation[]>;

updateAnnotationReply(
  reply: CPDFReplyAnnotation,
  options: { content: string; title?: string }
): Promise<boolean>;

removeAnnotationReply(reply: CPDFReplyAnnotation): Promise<boolean>;

removeAllAnnotationReplies(annotation: CPDFAnnotation): Promise<boolean>;

setAnnotationMarkState(
  annotation: CPDFAnnotation,
  state: CPDFAnnotationMarkState
): Promise<boolean>;

getAnnotationMarkState(
  annotation: CPDFAnnotation
): Promise<CPDFAnnotationMarkState>;

setAnnotationReviewState(
  annotation: CPDFAnnotation,
  state: CPDFAnnotationReviewState
): Promise<boolean>;

getAnnotationReviewState(
  annotation: CPDFAnnotation
): Promise<CPDFAnnotationReviewState>;

API description:

APIDescription
addAnnotationReplyAdds a plain reply to an annotation
getAnnotationRepliesGets all plain replies attached to an annotation
updateAnnotationReplyUpdates the content and optional title of a plain reply
removeAnnotationReplyRemoves one plain reply
removeAllAnnotationRepliesRemoves all plain replies attached to an annotation
setAnnotationMarkStateSets the mark state of an annotation or reply
getAnnotationMarkStateGets the mark state of an annotation or reply
setAnnotationReviewStateSets the review state of an annotation or reply
getAnnotationReviewStateGets the review state of an annotation or reply

Reply Model

Annotation replies are represented by CPDFReplyAnnotation.

ts
class CPDFReplyAnnotation extends CPDFAnnotation {
  modifyDate: Date | null;
}

Because CPDFReplyAnnotation extends CPDFAnnotation, it includes common annotation fields used in review workflows:

PropertyDescription
pageZero-based page index
titleReply author or title
contentReply content
createDateReply creation time, if provided by the native SDK
modifyDateReply modification time, if provided by the native SDK
markStateCurrent mark state
reviewStateCurrent review state

When updating, removing, or setting the state of a reply, use a CPDFReplyAnnotation object returned by addAnnotationReply or getAnnotationReplies. Do not manually construct a CPDFReplyAnnotation and pass it to these APIs.

Mark States and Review States

Mark states:

ts
enum CPDFAnnotationMarkState {
  MARKED = "marked",
  UNMARKED = "unmarked",
}

Review states:

ts
enum CPDFAnnotationReviewState {
  ACCEPTED = "accepted",
  REJECTED = "rejected",
  CANCELLED = "cancelled",
  COMPLETED = "completed",
  NONE = "none",
  ERROR = "error",
}

Mark states and review states can be set on the parent annotation or on a reply annotation:

tsx
await document.setAnnotationMarkState(
  annotation,
  CPDFAnnotationMarkState.MARKED
);

await document.setAnnotationReviewState(
  annotation,
  CPDFAnnotationReviewState.ACCEPTED
);

Get an Annotation Object

Most reply operations start from an existing annotation. The following example gets the first annotation on page 1.

tsx
const page = document.pageAtIndex(0);
const annotations = await page.getAnnotations();

if (!annotations.length) {
  return;
}

const annotation = annotations[0];

Page indexes are zero-based.

Add a Reply

Use addAnnotationReply to add a plain reply to an annotation.

tsx
const reply = await document.addAnnotationReply(annotation, {
  content: "Please review this highlight.",
  title: "Alex",
});

if (!reply) {
  throw new Error("Add annotation reply failed.");
}

console.log("Reply content:", reply.content);

content is required. title is optional and is commonly used as the reply author name.

Read Replies

Use getAnnotationReplies to get all plain replies attached to an annotation.

tsx
const replies = await document.getAnnotationReplies(annotation);

for (const reply of replies) {
  console.log("Author:", reply.title);
  console.log("Content:", reply.content);
  console.log("Mark state:", reply.markState);
  console.log("Review state:", reply.reviewState);
}

The returned list contains plain replies only. Internal state replies used to store mark and review states are not exposed as separate reply items.

Update a Reply

Use updateAnnotationReply to update the content and optional title of an existing reply.

tsx
const replies = await document.getAnnotationReplies(annotation);

if (replies.length) {
  const success = await document.updateAnnotationReply(replies[0], {
    content: "Updated reply content.",
    title: "Alex",
  });

  if (!success) {
    throw new Error("Update annotation reply failed.");
  }
}

The reply parameter should come from getAnnotationReplies or addAnnotationReply.

Remove One Reply

Use removeAnnotationReply to remove one plain reply.

tsx
const replies = await document.getAnnotationReplies(annotation);

if (replies.length) {
  const success = await document.removeAnnotationReply(replies[0]);

  if (!success) {
    throw new Error("Remove annotation reply failed.");
  }
}

Remove All Replies

Use removeAllAnnotationReplies to remove all plain replies attached to an annotation.

tsx
const success = await document.removeAllAnnotationReplies(annotation);

if (!success) {
  throw new Error("Remove all annotation replies failed.");
}

This API removes plain replies only. Mark state and review state information is preserved.

Set Mark and Review States on a Reply

You can set the mark state or review state of a reply.

tsx
const replies = await document.getAnnotationReplies(annotation);

if (replies.length) {
  const reply = replies[0];

  await document.setAnnotationMarkState(
    reply,
    CPDFAnnotationMarkState.MARKED
  );

  await document.setAnnotationReviewState(
    reply,
    CPDFAnnotationReviewState.COMPLETED
  );
}

After setting a reply state, call getAnnotationReplies again if the UI needs the latest reply data.

Set States on the Parent Annotation

You can also set mark and review states directly on the parent annotation.

tsx
await document.setAnnotationMarkState(
  annotation,
  CPDFAnnotationMarkState.MARKED
);

await document.setAnnotationReviewState(
  annotation,
  CPDFAnnotationReviewState.ACCEPTED
);

const markState = await document.getAnnotationMarkState(annotation);
const reviewState = await document.getAnnotationReviewState(annotation);

console.log("Mark:", markState);
console.log("Review:", reviewState);

Use in CPDFReaderView

In a reader screen, call the same APIs through pdfReaderRef.current?._pdfDocument.

tsx
import {
  CPDFReaderView,
  CPDFAnnotationReviewState,
} from "@compdfkit_pdf_sdk/react_native";

async function addReplyToFirstAnnotation(reader: CPDFReaderView) {
  const document = reader._pdfDocument;
  const pageIndex = await reader.getCurrentPageIndex();
  const annotations = await document.pageAtIndex(pageIndex).getAnnotations();

  if (!annotations.length) {
    return;
  }

  const reply = await document.addAnnotationReply(annotations[0], {
    content: "Reviewed in the reader.",
    title: "Reviewer",
  });

  if (reply) {
    await document.setAnnotationReviewState(
      reply,
      CPDFAnnotationReviewState.COMPLETED
    );
  }
}

This approach is suitable for custom review panels, annotation lists, and collaboration toolbars.

Complete Example

The following example gets the first annotation on page 1 in a reader, adds a reply, sets the review state on that reply, and reads the reply list again.

tsx
import {
  CPDFReaderView,
  CPDFAnnotation,
  CPDFReplyAnnotation,
  CPDFAnnotationReviewState,
} from "@compdfkit_pdf_sdk/react_native";

async function reviewFirstAnnotation(reader: CPDFReaderView) {
  const document = reader._pdfDocument;
  const page = document.pageAtIndex(0);
  const annotations: CPDFAnnotation[] = await page.getAnnotations();

  if (!annotations.length) {
    return;
  }

  const annotation = annotations[0];

  const reply: CPDFReplyAnnotation | null =
    await document.addAnnotationReply(annotation, {
      content: "Please verify this annotation.",
      title: "Reviewer",
    });

  if (!reply) {
    throw new Error("Add annotation reply failed.");
  }

  await document.setAnnotationReviewState(
    reply,
    CPDFAnnotationReviewState.COMPLETED
  );

  const replies = await document.getAnnotationReplies(annotation);

  console.log("Reply count:", replies.length);
}

Notes

  • When updating or removing a reply, use the CPDFReplyAnnotation object returned by the SDK.
  • Do not rely on internal annotation identifiers in application logic. Pass SDK-returned annotation or reply objects directly when operating on annotations or replies.
  • getAnnotationReplies returns plain replies only. State replies are handled internally by the SDK.
  • removeAllAnnotationReplies removes plain replies and preserves mark state and review state information.
  • After setting mark or review states, read the annotation or replies again if the UI needs the latest model data.
  • Annotation and reply APIs use zero-based page indexes.
  • To persist changes to the PDF file, save the document after completing the operations.