Blog Post

React PDF Annotations — A Complete Overview

Hussain Arif
Illustration: React PDF Annotations — A Complete Overview

In this post, we’ll cover different types of PDF annotations and their potential use cases, and we’ll also show you how to implement PDF annotations in your applications using PSPDFKit’s React PDF annotation library with the React API.

What Are PDF Annotations?

PDF annotations are objects — like text, graphics, highlights, text boxes, etc. — that you can add to a PDF document without changing the content. They’re useful for reviewing documents, collaborating with others, and implementing interactive features such as forms.

Normally, to annotate a document, you’d open a PDF in a third-party PDF editor and select an annotation tool.

Drawing on a PDF

But in place of an app, you can annotate PDF documents using frontend React code.

This means everything is run on the client side and not on an external server. This is useful in situations where user privacy is important, since the server isn’t processing any sensitive data.

Types of PDF Annotations in React

The PDF specification supports many types of annotations. They come in two categories:

  • Markup annotations — These are used to mark up the content of a PDF file. They’re typically used during a review process to allow your users to collaborate, emphasize parts of the text, and take notes.

  • Non-markup annotations — These are used for non-markup purposes such as adding multimedia or fillable form fields to an existing PDF.

The following sections will provide a quick overview of the various types of PDF annotations.

Text Markup

Text markup is used to annotate text in a PDF document. It can include highlighters, underlines, or strikeout annotations.

Text with highlighting, underlining, and strikeout annotations

Drawing Annotations

Drawing annotations are used to draw and write on a PDF page. You can customize the color, thickness, and transparency of the annotation tool.

Drawing on a PDF, with the toolbar showing the annotation tool options

Widget Annotations

Widgets are non-markup annotations. They appear in interactive forms, which include buttons, radio buttons, text fields, signature form fields, list boxes, and combo boxes. They can be used to create forms from flat documents.

A PDF form being filled in with typed text

Shape Annotations

These annotation types allow you to add a shape like a circle, box, or arrow annotation to a document. Cloudy annotations are commonly used in construction software to indicate a change in a plan.

Measurement Annotations

With measurement tools, users can calculate dimensions, measure distances between lines, or trace the perimeter of drawings in a PDF document. To ensure accuracy, the scale of measurement can be changed to match the scale of the document.

Text Annotations

This annotation type lets a user add text to a document. Users can do this by inserting a sticky note, adding a comment, or clicking and dragging a freeform text box.

Stamp Annotations

These annotation types allow users to quickly indicate the status of a document by — for example — adding an Approved or Declined stamp. They can also be used as a call to action in a document, where a user could add a stamp for a next step, such as Needs Signature.

Image Annotations

This type of annotation allows a user to upload and resize an image in their PDF. It can be used to quickly replace images within a document.

You can learn more about annotation types in this blog post.

Annotating in the UI vs. Programmatically

There are two ways to annotate PDF files: UI-based annotation and code-based annotation.

UI Annotation

With this method, the user selects an annotation tool in a PDF viewer and modifies a file manually.

Adding annotations in a PDF viewer

Programmatic Annotation

With programmatic annotation, a document is annotated automatically based on predefined rules written in the code. Programmatic annotation can be performed as part of an automation workflow or during runtime when a PDF is opened, or it can be manually triggered by the user.

Adding annotations programmatically

This way of handling annotations is necessary for the following situations:

  • Automation workflow — Governments and banks use automation software to stamp and insert timestamps on digital documents, which makes the process quicker and more efficient.

  • User-triggered events — If a user inputs text into a text field, the PDF runs JavaScript code to verify whether the data matches a predefined format. This ensures validation is done during runtime with zero human error.

  • Customization — Some PDF programs apply personal logos and convert text into clickable links.

Adding React PDF Annotations to Your Solution

There are two primary ways of adding React PDF annotation capabilities to your solution, and this next section will outline them.

Building Your Own React PDF Annotation Solution

One of the challenges of building your own solution is that there are currently no open source annotation libraries available. In all likelihood, you’ll need to start from scratch when building annotations into your application or software.

It’s important to understand that PDF documents are incredibly complex file formats — the PDF specification has more than 1,000 pages. As such, you’ll need to have a general understanding of PDFs to build the logic of adding an annotation to a layer over a document at a precise point. This process typically involves deploying, testing, and continually refining the logic until it’s reasonably accurate.

Once you’ve developed the logic, you’ll need to design the UI and icons for the annotation function in your app. This process involves first defining your toolbar layout, and then building it to account for both small and large screens.

The last factor involves maintaining your custom annotation solution over time. We’ve heard from customers who have built their own custom annotation solution on top of PDF.js — which is an open source JavaScript library built by Mozilla — and then struggled maintaining the project. With each new release, they needed to divert developers from working on their current tasks to spending time fixing bugs.

Commercial Options for PDF Annotations with React

Since developing a document annotator can be a time-consuming endeavor, you may want to look for an out-of-the-box commercial solution. This is where PSPDFKit’s React PDF annotation library could be useful.

It offers:

  • 17 annotation types, with more to come.

  • The ability to customize annotations — for example, you can change the color, shape, and size.

  • The ability to sync annotations between devices (requires server deployment).

  • Comment threads you can enable so your user can have real-time conversations in a document (requires server deployment).

  • Tooltips, which can be designed according to your needs.

  • Support for a plethora of web frameworks. This means the client doesn’t have to write APIs for multiple programming languages.

You can view our demo to see what PSPDFKit is capable of and determine how you can use it for your project.

Integrating PSPDFKit Annotations in React

Now that you’ve learned all about annotations, in this section, you’ll use our React API to work with annotations. Since PSPDFKit supports many frameworks, you can even use JavaScript or Angular, since their code samples are similar to the ones shown in this post.

Requirements

  • At least Node version 10.0 and npm version 6. However, we recommend running your code using the latest LTS release.

  • A code editor of your choice.

  • macOS 10.10 or Windows 7, or any Linux distribution that’s currently supported.

Project Setup

As a first step, initialize a project with npm:

npx create-react-app react-pspdf # create react app
cd react-pspdf
cd src
mkdir components
cd components
touch PDFViewer.js # Will render your document to the client’s browser.
cd .. # Go back to the `src` directory.

Next, since this app will be using the pspdfkit library, install it in your project:

npm install pspdfkit

It’s necessary to import certain styling code that will help PSPDFKit render your PDF to the browser:

cd .. # Navigate to the root directory.
# Get styles and other external libraries so you can use them in your project.
cp -R ./node_modules/pspdfkit/dist/pspdfkit-lib public/pspdfkit-lib

When that’s done, navigate to your public directory. Here, add a PDF file of your choice for annotation purposes. You can use this demo document as an example,

Now, create a new file within your src folder called helperFunctions.js. As the name suggests, this file will hold utility methods needed to embed annotations into your project.

In the end, your folder structure will look like this:

Folder structure

Mounting PDFs

In this section, you’ll write the code to render a PDF to the client interface.

Begin by adding this code to helperFunctions.js:

async function loadPDF({ PSPDFKit, container, document }) {
	const instance = await PSPDFKit.load({
		// Container where PSPDFKit should be mounted.
		container,
		// The document to open.
		document,
		// Use the public directory URL as a base URL. PSPDFKit will download its library assets from here.
		baseUrl: `${window.location.protocol}//${window.location.host}/${process.env.PUBLIC_URL}`,
	});
	return instance;
}
export { loadPDF }; // Export this method so you can use it in your project.
  • In this block of code, you created a function called loadPDF.

  • When React executes this function, the app will call the PSPDFKit.load method. Consequently, the library will now display the document to the UI.

All that’s left is to use your newly created function within your app. To do so, go to PDFViewer.js and paste this snippet:

import { useEffect, useRef } from 'react';
import { loadPDF } from './helperFunctions'; // Import the `loadPDF` function.
function PDFViewer(props) {
	const containerRef = useRef(null); // Will serve as your container to render the document.
	useEffect(() => {
		let PSPDFKit;
		const container = containerRef.current;
		(async function () {
			PSPDFKit = await import('pspdfkit');

			PSPDFKit.unload(container); // Ensure that there's only one PSPDFKit instance.

			const instance = await loadPDF({
				// Invoke the `loadPDF` function.
				PSPDFKit,
				container,
				document: props.document, //get the document location from the prop.
			});
		})();
		// When the user closes the app, remove the PDF from RAM.
		// This prevents memory leaks.
		return () => PSPDFKit && PSPDFKit.unload(container);
	}, []);
	// Your PDF will be rendered within this PDF.
	return (
		<div
			ref={containerRef}
			style={{ width: '100%', height: '100vh' }}
		/>
	);
}
export default PDFViewer;

As the last step, render the PDFViewer component to the DOM. To do so, write this snippet in your App.js file:

import PDFViewer from './PDFViewer';
function App() {
	return (
		<div className="App">
			<PDFViewer document={'Document.pdf'} />{' '}
			{/*Render the Document.pdf file*/}
		</div>
	);
}
export default App;

Now it’s time to test it out! To run this React app, use this bash command:

npm run start

The final result will look like this:

Mount PDFs React PDF Annotations

Adding Text Annotations

PSPDFKit uses the PSPDFKit.Annotations.TextAnnotation class for embedding text annotations.

To use text annotations, enter the following block of code in the helperFunctions.js file:

async function createTextAnnotation({ PSPDFKit, instance }) {
	const annotation = new PSPDFKit.Annotations.TextAnnotation({
		pageIndex: 0, // Which page number should have this annotation.
		text: {
			format: 'plain',
			value: 'Welcome to\nPSPDFKit',
		}, // Text to embed.
		font: 'Helvetica',
		isBold: true,
		horizontalAlign: 'center', // Align your annotation to the center of the box.
		boundingBox: new PSPDFKit.Geometry.Rect({
			// Position of this annotation.
			left: 50,
			top: 200,
			width: 100,
			height: 80,
		}),
		fontColor: PSPDFKit.Color.GREEN, // color of the text
	});

	// Attach this annotation to your PDF:
	const createdAnnotation = await instance.create(annotation);
	return createdAnnotation;
}
export { createTextAnnotation }; // Finally, export this function.

When that’s done, all that’s left is to use your newly created helper function. To make this possible, write this line at the end of the async function in PDFViewer.js just after the loadPDF function:

// `src/PDFViewer.js`

import { createTextAnnotation } from './helperFunctions.js';
useEffect(() => {
	// More code.
	createTextAnnotation({ PSPDFKit, instance });
}, []);

This will be the result:

Adding text annotations to a PDF

Creating Ink Annotations

To insert ink annotations, use the PSPDFKit.Annotations.InkAnnotation class. In helperFunctions.js, add the following:

async function createInkAnnotation({
	PSPDFKit,
	instance,
	x1,
	y1,
	x2,
	y2,
}) {
	// Extract the `List`, `DrawingPoint`, `Rect`, and `InkAnnotation` properties from PSPDFKit.
	// These are needed to render annotations onto the screen.
	const { List } = PSPDFKit.Immutable;
	const { DrawingPoint, Rect } = PSPDFKit.Geometry;
	const { InkAnnotation } = PSPDFKit.Annotations;
	// Create your ink annotation.
	const annotation = new InkAnnotation({
		pageIndex: 0,
		boundingBox: new Rect({ width: 400, height: 100 }), //position of annotation
		strokeColor: new PSPDFKit.Color({ r: 255, b: 0, g: 255 }), //color of stroke
		lines: List([
			// Coordinates of stroke.
			List([
				new DrawingPoint({ x: x1, y: y1 }),
				new DrawingPoint({ x: x2, y: y2 }),
			]),
		]),
	});
	// Attach stroke to annotation:
	const createdAnnotation = await instance.create(annotation);
	return createdAnnotation;
}
export { createInkAnnotation };

As the last step, run the createInkAnnotation function in the PDFViewer.js module:

// `src/PDFViewer.js`

useEffect(( )=> {
  // More code.
  // Draw a line from (5,5) to (100,100):
  await createInkAnnotation({
    PSPDFKit,
    instance,
    x1: 5,
    y1: 5,
    x2: 100,
    y2: 100,
  });
}, [ ]);

This will be the outcome:

Adding ink annotations to a PDF

Exporting to XFDF

An XFDF file is an Adobe forms document that stores PDF-usable information. The data is written in XML.

You can export your modified document into XFDF via the exportXFDF method within the PDFViewer.js module:

useEffect(()=> {
// More code.
  const XFDFData = await instance.exportXFDF(); 		// Procure XFDF data.
  console.log(XFDFData);				 	// Log XML data to the console.
}, [ ]);

This will be the result:

XFDF version of the PDF

Setting the Annotations Author

You can set the annotation author’s name via the setAnnotationCreatorName function:

instance.setAnnotationCreatorName('Name');

Conclusion

In this post, you learned all about PDF annotations, and you saw how to use PSPDFKit’s solutions to implement programmatic annotations in React. You can find the source code here.

If you want to learn more about PSPDFKit, you can request a free trial of our SDK, or browse our demo page to see what our API is capable of.

Related Products
Share Post
Free 60-Day Trial Try PSPDFKit in your app today.
Free Trial

Related Articles

Explore more
PRODUCTS  |  Web • Annotations

Supported Annotation Flags in the PDF Spec and PSPDFKit

TUTORIALS  |  Web • Angular • How To • Annotations

How to Add Annotations to PDFs Using Angular

TUTORIALS  |  Android • Annotations • How To

How to Add Annotations to PDFs Using the Android Library