How to Build a React PDF Viewer with Annotation Support

Dynamsoft Document Viewer is an SDK providing a set of viewers for document images. We can use it to incorporate PDF creating, viewing and annotating into our web apps. In this article, we are going to build a fully functional PDF viewer and annotator in a React + TypeScript project.

What you’ll build: A React web app that can create, view, and annotate PDF documents using the Dynamsoft Document Viewer SDK, complete with a toolbar, thumbnail panel, and annotation tools.

Key Takeaways

  • Dynamsoft Document Viewer provides a drop-in React-compatible component for PDF viewing, annotation, and creation with minimal setup code.
  • The EditViewer class renders a full-featured document editor with built-in annotation tools, thumbnail navigation, and image filters.
  • WASM engine resources must be copied to the public folder at build time — the ncp package automates this in both dev and production workflows.
  • This approach works for any React + TypeScript project scaffolded with Vite and can be extended with programmatic document manipulation via the SDK’s API.

Common Developer Questions

  • How do I add a PDF viewer with annotation support to a React app?
  • What is the easiest way to create and edit PDFs in a React TypeScript project?
  • How do I integrate Dynamsoft Document Viewer into a Vite-based React application?

Prerequisites

Step 1: Create a New React Project

Create a new React + TypeScript project with Vite:

npm create vite@latest pdf-app -- --template react-ts

Step 2: Install Dynamsoft Document Viewer

First, install Dynamsoft Document Viewer via npm.

npm install dynamsoft-document-viewer

Then, we need to copy the resources of Dynamsoft Document Viewer to the public folder.

  1. Create a new folder under public/assets/ddv-resources.
  2. Install ncp: npm install ncp --save-dev.
  3. Modify package.json to copy the resources from node_modules to the public folder.

    - "dev": "vite",
    - "build": "tsc -b && vite build",
    + "dev": "ncp node_modules/dynamsoft-document-viewer/dist public/assets/ddv-resources && vite",
    + "build": "ncp node_modules/dynamsoft-document-viewer/dist public/assets/ddv-resources && tsc -b && vite build",
    

Step 3: Initialize the SDK with a License Key

Let’s rewrite App.tsx. When it is mounted, initialize Dynamsoft Document Viewer with a license. You can apply for a license here.

const initializing = useRef(false);
const editViewer = useRef<EditViewer|undefined>();
useEffect(()=>{
  if (initializing.current == false) {
    initializing.current = true;
    initDDV();
  }
},[])

const initDDV = async () => {
  DDV.Core.license = "LICENSE-KEY"; // Public trial license which is valid for 24 hours
  DDV.Core.engineResourcePath = "assets/ddv-resources/engine";// Lead to a folder containing the distributed WASM files
  await DDV.Core.loadWasm();
  await DDV.Core.init(); 
  // Configure image filter feature which is in edit viewer
  DDV.setProcessingHandler("imageFilter", new DDV.ImageFilter());
}

Step 4: Create an Edit Viewer with Annotation Support

  1. Use the following in the JSX:

    return (
      <div id="app">
        <h2>Document Viewer Demo</h2>
        <div id="container"></div>
      </div>
    )
    

    CSS:

    #app {
      display: flex;
      align-items: center;
      flex-direction: column;
      width: 100%;
    }
    
    #container {
      max-width: 80%;
      width: 1280px;
      height: 480px;
    }
    
  2. Initialize an instance of Edit Viewer and bind it to a container via its ID.

    const config = DDV.getDefaultUiConfig("editViewer", {includeAnnotationSet: true}) as UiConfig;
    // Create an edit viewer
    editViewer.current = new DDV.EditViewer({
      container: "container",
      uiConfig: config,
    });
    
  3. Import the CSS of Dynamsoft Document Viewer.

    import "dynamsoft-document-viewer/dist/ddv.css";
    

All right, we’ve incorporated Dynamsoft Document Viewer in our React app.

React Demo

The viewer provides a toolbar, a thumbnail viewer and a main viewer for the document. We can click the buttons on the toolbar to load a new image, edit images, add PDF annotations and save the document as a PDF file.

Apart from the UI, we can also manipulate the document via code. Read the docs to learn more.

Common Issues and Edge Cases

  • WASM files not found at runtime: If the viewer fails to load, verify that the ncp copy step ran before the dev server started. Check that public/assets/ddv-resources/engine contains the .wasm files. A missing or incorrect engineResourcePath is the most common setup error.
  • License key expired or invalid: The public trial key expires after 24 hours. Replace it with a valid trial or production key. An expired key results in a watermark overlay or an initialization error.
  • Viewer container has zero height: The EditViewer requires its container element to have an explicit height. If the viewer renders blank, inspect the container’s computed styles and ensure height is set (e.g., 480px).

Source Code

Check out the source code of the demo to have a try.

https://github.com/tony-xlh/document-viewer-samples/tree/main/frameworks/react/pdf-app