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
EditViewerclass 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
ncppackage 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
- Node.js 16 or later
- npm or yarn
- A Dynamsoft Document Viewer license. Get a 30-day free trial license to follow along.
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.
- Create a new folder under
public/assets/ddv-resources. - Install
ncp:npm install ncp --save-dev. -
Modify
package.jsonto copy the resources fromnode_modulesto 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
-
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; } -
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, }); -
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.

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
ncpcopy step ran before the dev server started. Check thatpublic/assets/ddv-resources/enginecontains the.wasmfiles. A missing or incorrectengineResourcePathis 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
EditViewerrequires its container element to have an explicit height. If the viewer renders blank, inspect the container’s computed styles and ensureheightis 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