Skip to content
ComPDF
DemoAPI ReferenceFAQ

PDF Generation Template Editor

Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.

View on GitHub
Guides

Annotations

Use these APIs for annotation property panels, creation and selection events, and annotation undo/redo state.

Reader APIs

Callback or APIParametersTrigger
onAnnotationStyleDialogDismissed{ type }The annotation properties panel closes.
reader._annotationsHistoryManager.
setOnHistoryStateChangedListener()
canUndo: boolean, canRedo: booleanThe annotation undo/redo state changes.

Event Listener API

CPDFReaderView supports multiple callbacks for the same CPDFEvent. Its public methods are:

tsx
addEventListener<K extends keyof CPDFEventDataMap>(
  event: K,
  callback: (eventData: CPDFEventDataMap[K]) => void,
): void;

removeEventListener<K extends keyof CPDFEventDataMap>(
  event: K,
  callback: (eventData: CPDFEventDataMap[K]) => void,
): void;

Annotation Events

EventEvent dataTrigger
CPDFEvent.ANNOTATIONS_CREATEDCPDFAnnotationA non-form annotation is created.
CPDFEvent.ANNOTATIONS_SELECTEDCPDFAnnotationAn annotation is selected.
CPDFEvent.ANNOTATIONS_DESELECTEDCPDFAnnotation | nullAn annotation is deselected.
CPDFEvent.PENCIL_DRAWING_COMPLETED{ type: 'pencil'; pageIndex: number }A Pencil drawing is saved (iOS only).
CPDFEvent.PENCIL_DRAWING_DISCARDED{ type: 'pencil'; pageIndex: number }A Pencil drawing is discarded (iOS only).

The public TypeScript contract for annotation deselection is nullable; handle a null value before accessing the object. Pencil events are available only on iOS, and the returned pageIndex is zero-based.

These events cover creation and selection state. They do not provide annotation update or delete events, and they do not report save failures.

Register and Remove Listeners

Register and remove the same stable function reference. Preserve the Reader instance used for registration because ref.current may already be null when an Effect cleanup runs.

tsx
const pdfReaderRef = useRef<CPDFReaderView | null>(null);
const subscribedReaderRef = useRef<CPDFReaderView | null>(null);

const onAnnotationCreated = useCallback((annotation: CPDFAnnotation) => {
  console.log('Created annotation:', annotation.type);
}, []);

const onViewCreated = useCallback(() => {
  const reader = pdfReaderRef.current;
  if (!reader || subscribedReaderRef.current === reader) {
    return;
  }

  subscribedReaderRef.current = reader;
  reader.addEventListener(
    CPDFEvent.ANNOTATIONS_CREATED,
    onAnnotationCreated,
  );
}, [onAnnotationCreated]);

useEffect(() => {
  return () => {
    const reader = subscribedReaderRef.current;
    if (!reader) {
      return;
    }

    reader.removeEventListener(
      CPDFEvent.ANNOTATIONS_CREATED,
      onAnnotationCreated,
    );
    subscribedReaderRef.current = null;
  };
}, [onAnnotationCreated]);

removeEventListener() returns void. RN does not provide removeAllEventListeners() and does not stop native event generation when the last JavaScript listener is removed. The local Listener Map is released with the Reader instance; explicit removal is most important when an Effect reruns or the Reader remains mounted.