PDF.js Express Plusplay_arrow

Professional PDF.js Viewing & Annotations - Try for free

side menu

Get Started

play_arrow

Learn more

play_arrow

Common use cases

play_arrow

Open a document

play_arrow

Save a document

play_arrow

Viewer

play_arrow

UI Customization

play_arrow

Annotations

play_arrow

Collaboration

play_arrow

Forms

play_arrow

Signature

play_arrow

Searching

play_arrow

Measurement

play_arrow

Compare

play_arrow

Advanced Capabilities

play_arrow

PDF.js Express REST API

play_arrow

Migration Guides

play_arrow

Events for PDF.js Express

The following features are available in:

check

PDF.js Express Viewer

help_outline

PDF.js Express Viewer is a free viewer with limited capabilities compared to PDF.js Express Plus

check

PDF.js Express Plus

help_outline

PDF.js Express Plus is a commercial PDF SDK for viewing, annotating, signing, form filling and more

This guide will go over the order of events that happen when PDF.js Express Web Viewer is instantiated and a document is loaded.

Here is a complete visualization of the order of events that occur. For a more detailed description, see the sections below.

Instantiation and resource loading

The first step you take when implementing PDF.js Express is creating a new instance of WebViewer. This is done with the WebViewer function, like so:

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'  // Local URI or to file on web server
}, document.getElementById('viewer')).then(instance => {
  // call APIs here
});

PDF.js Express then creates an iframe in the DOM element that you provide, and starts loading all the necessary resources in that iframe, including the UI and web workers.

When those resources are finished loading and PDF.js Express can be interacted with, the promise resolves with an instance of PDFJS Express.

viewerElement.ready

Once the promise is resolved, you can begin to interact with PDF.js Express. This includes UI customizations, loading documents, subscribing to other PDF.js Express events, and any other functionality you may want to use.

Keep in mind that at this point, the document (if one was provided) has not been loaded and cannot be interacted with yet. See document loading for more info.

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'
}, document.getElementById('viewer'))
  .then(instance => {
    // you can disable annotations 
    instance.UI.disableFeatures([instance.UI.Feature.Annotations])

    // or customize the UI
    instance.UI.setTheme({ primary: 'blue', secondary: 'white' });

    // etc..
  });

Document loading

Once all the required PDF.js Express resources are loaded, documents can start loading. You can load a document either by passing one to the initialDoc constructor option, or calling loadDocument in the ready callback (as seen above).

The first step of loading a document is loading all, or part, of the document into memory. Once we have enough information about the document stored in memory, the first document lifecycle event is called, DocumentViewer.documentLoaded.

DocumentViewer.documentLoaded

This event is called when the document is loaded into memory and you can start interacting with the document. This includes loading annotations, initializing collaboration, and more!

You can bind to the event like so:

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'
}, document.getElementById('viewer'))
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;

    documentViewer.addEventListener('documentLoaded', () => {
      // here you can get the document and perform actions on it,
      // such as removing pages
      documentViewer.getDocument().removePages([2]).then(() => { })


      // or importing annotations from your server
      getAnnotationsFromServer(DOCUMENT_ID).then(async xfdfString => {
        const annotations = await annotationManager.importAnnotations(xfdfString);
        annotationManager.drawAnnotationsFromList(annotations);
      });
    })
  });

Keep in mind that this callback gets fired for every document that gets loaded throughout the life of your app. If you want the callback to only be fired once, you can unsubscribe from the event like so:

WebViewer(...)
  .then(instance => {
    const documentViewer = instance.Core.documentViewer;

    const callback = () => { 
      // unsubscribe after invoking
      docViewer.removeEventListener('documentLoaded', callback);
    }

    docViewer.addEventListener('documentLoaded', callback);

    // or

    docViewer.one('documentLoaded', () => { });
  })

Document Load Error Handling

On the other hand, if a document fails to load, a loaderror event will be triggered on the iframe window. Although WebViewer can recover from most loading errors, you may want to show a custom error message, submit a log to an API, and/or load a new document.

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'
}, document.getElementById('viewer'))
  .then((instance) => {
    instance.UI.iframeWindow.addEventListener('loaderror', (err) => {
      // Do something with error. eg. instance.showErrorMessage('An error has occurred')
    });
  });

Document and annotation rendering

After the document is in memory, we are ready to start rendering to the screen. The document and its annotations are rendered in parallel, and there are two main events that are fired during this cycle.

DocumentViewer.pageComplete

This event is fired for each page that is rendered. We only render the pages that are visible on the screen, so this event won't get fired for every page in the document at once. This event will get called when the user scrolls up and down the document, or when a page is zoomed or rotated, or anything else that makes it re-render.

A few extra pages may be prerendered at lower priority, so pageComplete may be called for pages that are not currently visible. You can set the prerender level with the SetPreRenderLevel function.

You can subscribe to this event similar to how you subscribe to the documentLoaded event (as seen in the previous section).

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'
}, document.getElementById('viewer'))
  .then(instance => {
    const { documentViewer } = instance.Core;


    documentViewer.addEventListener('pageComplete', (pageNumber, canvas) => {
      // here it's guaranteed that page {pageNumber} is fully rendered
      // you can get or set pixels on the canvas, etc
    })
  });

Remember that this callback is fired for every page on every document that is loaded. You can unsubscribe using the off function (as seen in the previous section).

DocumentViewer.annotationsLoaded

This event is fired when all the annotations have been loaded into memory. At this point you can start interacting with the annotations, such as saving and loading.

We load annotations asynchronously in the background, and they may be rendered before this event is fired.

You can subscribe to the event like so:

WebViewer({
  initialDoc: 'https://myserver.com/myfile.pdf'
}, document.getElementById('viewer'))
  .then(instance => {
    const { documentViewer, annotationManager } = instance.Core;

    documentViewer.addEventListener('annotationsLoaded', async () => {
      // here you can start interacting with annotations,
      // like saving the original annotations to your server

      const xfdfString = await annotationManager.exportAnnotations({ widgets: false });
      saveAnnotsStringToServer(xfdfString);
    })
  });