Blog post

How to build a React PDF viewer using react-pdf

In this blog post, you’ll learn how to build a React.js PDF viewer using the react-pdf library and Nutrient. react-pdf is a widely used open source library designed for rendering PDF files in React applications, while Nutrient provides a powerful, feature-rich solution for viewing, annotating, and editing PDFs.

Illustration: How to build a React PDF viewer using react-pdf

Before diving into react-pdf and Nutrient, you’ll explore native HTML elements like <iframe>, <embed>, and <object>, which allow you to display PDFs in React applications without additional libraries. While these methods are quick and easy to implement, they have limitations in terms of customization and interactivity.

This blog post is structured into three main parts:

  1. Embedding PDFs using native HTML elements — Learn how to display PDFs with <iframe>, <embed>, and <object> and compare their pros and cons.

  2. Building a React PDF viewer with react-pdf — A step-by-step guide on integrating react-pdf into your project to create a fully functional PDF viewer.

  3. Exploring Nutrient for qdvanced PDF reatures — Discover how Nutrient extends React’s PDF viewing capabilities with annotations, form filling, and more.

Embedding PDFs in React apps using iframe, embed, and object

If you don’t need advanced features like annotations or custom UI controls, you can easily embed PDF documents into your React application using standard HTML tags like <iframe>, <embed>, and <object>. These methods are simple to implement and don’t require additional libraries.

1. Using iframe

The <iframe> tag is one of the most common ways to embed a PDF in a web application. It allows you to display a PDF document within a frame on your page.

Example:

function PDFViewer() {
	return (
		<div>
			<h2>Embedding PDF with iframe</h2>
			<iframe
				src="/document.pdf"
				width="100%"
				height="1000px"
				title="PDF Viewer"
			/>
		</div>
	);
}

export default PDFViewer;

Pros

✔ Easy to implement
✔ Works across all modern browsers
✔ Supports responsive sizing

Cons

✘ Limited customization options
✘ No built-in controls for annotations or text selection

2. Using embed

The <embed> tag is another way to display a PDF directly in your React app. It’s straightforward and works similarly to <iframe>.

Example:

function PDFViewer() {
	return (
		<div>
			<h2>Embedding PDF with embed</h2>
			<embed
				src="/document.pdf"
				type="application/pdf"
				width="100%"
				height="1000px"
			/>
		</div>
	);
}

export default PDFViewer;

Pros

✔ Simple and lightweight
✔ Good for basic PDF display

Cons

✘ Limited browser support for advanced features
✘ No built-in navigation or annotation tools

3. Using object

The <object> tag is a more flexible way to embed PDFs. It can also be used to embed other types of media, like images or videos.

Example:

function PDFViewer() {
	return (
		<div>
			<h2>Embedding PDF with object</h2>
			<object
				data="/document.pdf"
				type="application/pdf"
				width="100%"
				height="1000px"
			>
				<p>
					Your browser does not support PDFs.{' '}
					<a href="/document.pdf">Download the PDF</a>.
				</p>
			</object>
		</div>
	);
}

export default PDFViewer;

Pros

✔ Provides a fallback option for unsupported browsers
✔ More flexible than <iframe> and <embed>

Cons

✘ Slightly more complex to implement
✘ Limited customization options

Comparison of embedding methods

Method Ease of use Customization Browser support Fallback option
<iframe> Easy Low Excellent No
<embed> Easy Low Good No
<object> Moderate Moderate Excellent Yes

When to use these methods

These embedding methods are ideal for:

  • Simple PDF display — If you only need to display a PDF without advanced features.

  • Quick prototyping — When you want to test or prototype a feature without installing additional libraries.

  • Lightweight applications — For projects where minimizing dependencies is a priority.

Limitations of embedding PDFs

While these methods are simple, they come with limitations:

  • No custom UI — You can’t easily add custom navigation controls, annotations, or search functionality.

  • Limited interactivity — Users can’t interact with a PDF beyond basic viewing.

  • Performance issues — Large PDFs may load slowly or cause performance issues in the browser.

For more advanced PDF rendering in React, you can use dedicated libraries like react-pdf or Nutrient.

Open source React PDF viewer libraries

For more advanced PDF rendering in React, you can use dedicated libraries. Below are two popular options.

@react-pdf/renderer

  • Use case — Creating PDFs in React (browser, server, or mobile).

  • Popularity — ~510K weekly downloads on npm.

  • Guide — Check out our how to create a PDF with React.js tutorial.

react-pdf

  • Use case — Displaying existing PDFs in a React app.

  • Popularity — ~950K weekly downloads on npm.

  • Guide — This blog post will walk you through integrating react-pdf to build a custom React PDF viewer.

Why choose react-pdf for your React PDF viewer?

react-pdf is an excellent choice for developers who want to integrate PDF viewing functionality into their React applications. Here are some key benefits:

Ease of integrationreact-pdf offers a simple and straightforward API, making it easy to add PDF viewing capabilities to existing React projects. You can quickly display PDFs with minimal setup.

Flexibility — The library provides components like Document and Page, enabling developers to create custom PDF viewers. The Document component is essential for loading PDF files, and for optimized performance, its recommended to define any configuration options outside the React component using hooks like useMemo.

Customization — While react-pdf doesn’t include a built-in UI, this flexibility allows you to create a user interface tailored to your application’s design. You can add navigation controls, zoom functionality, and other features using standard React components.

Compatibility — As a pure React library, react-pdf is fully compatible with the React ecosystem. Whether you’re using hooks, context, or other React features, react-pdf integrates seamlessly.

Community support — With around 950K weekly downloads on npm, react-pdf has a large and active community. This means you can find ample resources, examples, and support from other developers who use the library.

The next section will provide step-by-step instructions on how to build a React PDF viewer with react-pdf.

Requirements to get started

To get started, you’ll need:

  • Node.js version 14 or later.

  • A package manager compatible with npm. This guide contains usage examples for Yarn and the npm client (installed with Node.js by default). Make sure the npm version is 5.6 or greater.

Building a React.js PDF viewer with react-pdf

Start by creating a React.js project with vite:

npm create vite@latest react-pdf-demo -- --template react

After the project is created, change the directory into the project folder:

cd react-pdf-demo

Adding react-pdf

  1. Now, you can install the npm package for the react-pdf library from the terminal:

npm install react-pdf
  1. Place the file you want to render inside the public directory of the react-pdf-example project. You can use our demo document as an example; you just need to rename it to document.pdf.

Displaying a PDF

  1. react-pdf comes with two components: Document and Page. Document is used to open a PDF and is mandatory. Within the document, you can mount pages, which are used to render the PDF page. To integrate this into your example project, open src/App.jsx and replace its contents with the following:

import { useState } from 'react';
import { Document, Page } from 'react-pdf';

// Text layer for React-PDF.
import 'react-pdf/dist/Page/TextLayer.css';

const App = () => {
	const [numPages, setNumPages] = useState(null);
	const [pageNumber, setPageNumber] = useState(1);

	const onDocumentLoadSuccess = ({ numPages }) => {
		setNumPages(numPages);
	};

	const goToPrevPage = () =>
		setPageNumber(pageNumber - 1 <= 1 ? 1 : pageNumber - 1);

	const goToNextPage = () =>
		setPageNumber(
			pageNumber + 1 >= numPages ? numPages : pageNumber + 1,
		);

	return (
		<div>
			<nav>
				<button onClick={goToPrevPage}>Prev</button>
				<button onClick={goToNextPage}>Next</button>
				<p>
					Page {pageNumber} of {numPages}
				</p>
			</nav>

			<Document
				file="pspdfkit-web-demo.pdf"
				onLoadSuccess={onDocumentLoadSuccess}
			>
				<Page pageNumber={pageNumber} />
			</Document>
		</div>
	);
};

export default App;

For react-pdf to work, a PDF.js worker needs to be provided. You can do this in a couple of ways. For most cases, importing the worker will work, as was done in the src/App.jsx file:

import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
	'pdfjs-dist/build/pdf.worker.min.mjs',
	import.meta.url,
).toString();
// Rest of code.

You can read more about how to configure a PDF.js worker in your project here.

  1. Now, start the application by running the following:

npm run dev

One of the disadvantages of using react-pdf is that it doesn’t come with a UI. In this example, you’ve rendered two buttons to navigate between pages and showed the total number of pages.

Information

You can access the full code on GitHub.

Limitations of react-pdf

Overall, react-pdf is a great open source project, but it has some disadvantages:

  • It doesn’t come with a user interface out of the box. If you need a UI to help users navigate through a PDF, you’ll need to build it from scratch.
  • Text selection doesn’t work properly. If you try to select text in a PDF, you’ll see that it’s not a good user experience.
  • Rendering large PDF files or documents with many pages can sometimes impact performance, particularly in resource-constrained environments.

Building a React PDF viewer with Nutrient

We offer a commercial React.js PDF library that can easily be integrated into your web application. It comes with 30+ features that let you view, annotate, edit, and sign documents directly in your browser. Out of the box, it has a polished and flexible UI that you can extend or simplify based on your unique use case.

  • A prebuilt and polished UI
  • 15+ annotation tools
  • Support for multiple file types
  • Dedicated support from engineers

Creating a new React project

  1. Use vite to scaffold out a simple React application:

npm create vite@latest pspdfkit-react-example -- --template react
  1. Change to the created project directory:

cd pspdfkit-react-example

Adding Nutrient to your project

  1. Now, add Nutrient Web SDK as a dependency:

npm install pspdfkit
  1. As you’re using the WebAssembly build of Nutrient Web SDK, the final setup step is to copy files the browser will need from the npm module:

cp -R ./node_modules/pspdfkit/dist/pspdfkit-lib public/pspdfkit-lib

The code above will copy the pspdfkit-lib directory from within node_modules/ into the public/ directory to make it available to the SDK at runtime.

  1. Make sure your public directory contains a pspdfkit-lib directory with the Nutrient library assets.

Displaying a PDF

  1. Add the PDF document you want to display to the public directory. You can use our demo document as an example.

  2. Add a component wrapper for the Nutrient library and save it as src/components/ViewerComponent.jsx:

import { useEffect, useRef } from 'react';

export default function ViewerComponent(props) {
	const containerRef = useRef(null);

	useEffect(() => {
		const container = containerRef.current;
		let PSPDFKit;

		(async function () {
			PSPDFKit = await import('pspdfkit');
			PSPDFKit.unload(container);

			await PSPDFKit.load({
				// Container where PSPDFKit should be mounted.
				container,
				// Use dark theme.
				theme: PSPDFKit.Theme.DARK,
				// The document to open.
				document: props.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
				}/${import.meta.env.BASE_URL}`,
			});
		})();

		return () => PSPDFKit && PSPDFKit.unload(container);
	}, [props.document]);

	return (
		<div
			ref={containerRef}
			style={{ width: '100%', height: '100vh' }}
		/>
	);
}

To load Nutrient Web SDK into the ViewerComponent, use PSPDFKit.load when the component has mounted.

  1. Now, all that’s left is to render the ViewerComponent in App.jsx by loading the PDF you downloaded earlier:

import ViewerComponent from './components/ViewerComponent';

function App() {
	return (
		<div className="App" style={{ width: '100vw' }}>
			<div className="App-viewer">
				<ViewerComponent document={'document.pdf'} />
			</div>
		</div>
	);
}

export default App;
  1. You can also open a different PDF file by adding a button and adding a handler to the onClick event:

// App.jsx
import { useState } from 'react';

import ViewerComponent from './components/ViewerComponent';

function App() {
	const [document, setDocument] = useState('document.pdf');

	const handleOpen = () => setDocument('another-example.pdf');

	return (
		<div className="App" style={{ width: '100vw' }}>
			<button className="App-button" onClick={handleOpen}>
				Open another document
			</button>
			<div className="App-viewer">
				<ViewerComponent document={document} />
			</div>
		</div>
	);
}

export default App;

You can use this example document as a second example. Rename it to another-example.pdf, and then add it to the /public folder.

When you click Open another document, it loads the another-example.pdf file.

  1. Your project structure will now look like this:

pspdfkit-react-example
├── public
│   ├── pspdfkit-lib
│   └── document.pdf
│   └── another-example.pdf
├── src
│   ├── components
│   |   └── ViewerComponent.jsx
|   └── App.js
└── package.json
  1. Start the app and run it in your default browser:

npm run dev

You’ll now see your PDF rendered in the container element. Try using the toolbar to navigate through, annotate, and search in the document. Note that because Nutrient is a commercial product, you’ll see a Nutrient Web SDK evaluation notice on the document. To get a license key, contact Sales.

Information

You can find the finished code on GitHub.

Adding annotations

Now that you have a working React PDF viewer with Nutrient, you can extend its functionality by adding annotation support. Nutrient Web SDK includes built-in annotation tools, allowing users to highlight text, add comments, draw shapes, and more.

Update the ViewerComponent to include annotation creation. Here’s the updated component code that adds a text annotation to the PDF:

import { useEffect, useRef } from 'react';

export default function ViewerComponent({ document }) {
	const containerRef = useRef(null);

	useEffect(() => {
		const container = containerRef.current;
		let PSPDFKitInstance;

		(async function () {
			const PSPDFKit = await import('pspdfkit');
			if (PSPDFKitInstance) PSPDFKit.unload(container);

			PSPDFKitInstance = await PSPDFKit.load({
				container,
				document,
				theme: PSPDFKit.Theme.DARK,
				baseUrl: `${window.location.protocol}//${
					window.location.host
				}/${import.meta.env.BASE_URL}`,
			});

			// Add annotation support.
			createTextAnnotation(PSPDFKit, PSPDFKitInstance);
		})();

		return () =>
			PSPDFKitInstance && PSPDFKitInstance.unload(container);
	}, [document]);

	// Function to add text annotation.
	async function createTextAnnotation(PSPDFKit, instance) {
		const annotation = new PSPDFKit.Annotations.TextAnnotation({
			pageIndex: 0,
			text: {
				format: 'plain',
				value: 'Welcome to Nutrient PDF Viewer!',
			},
			font: 'Helvetica',
			isBold: true,
			horizontalAlign: 'center',
			boundingBox: new PSPDFKit.Geometry.Rect({
				left: 50,
				top: 200,
				width: 150,
				height: 50,
			}),
			fontColor: PSPDFKit.Color.BLUE,
		});

		await instance.create(annotation);
	}

	return (
		<div
			ref={containerRef}
			style={{ width: '100%', height: '100vh' }}
		/>
	);
}

This will add a text annotation to the first page of the PDF. You can adjust the properties as needed.

Check out React PDF annotations for more information on adding annotations to your React PDF viewer.

If you hit any snags, don’t hesitate to reach out to our Support team for help.

Why Nutrient is the best choice for your React PDF viewer

When it comes to building a robust PDF viewer in React, Nutrient stands out as the top choice. Here’s why:

  • Feature-rich SDK — Nutrient offers a comprehensive set of PDF viewing and editing features, including annotations, digital signatures, form filling, and more.

  • Out-of-the-box UI — Unlike open source alternatives like react-pdf, Nutrient provides a sleek and intuitive user interface, saving development time.

  • Performance optimized — Large PDFs render smoothly, ensuring a seamless experience, even with complex documents.

  • Multiple file format support — Beyond PDFs, Nutrient supports viewing and editing Word, Excel, and image files.

  • Enterprise-grade support — Get dedicated technical support and regular updates to keep your PDF viewer running at its best.

With Nutrient, you get a powerful and scalable solution that lets you deliver the best PDF experience to your users without compromising on performance or usability.

Conclusion

In this blog post, you learned how to build a React.js PDF viewer using the react-pdf library and Nutrient. While react-pdf offers a basic PDF viewing solution, Nutrient provides a more powerful, feature-rich alternative for not just viewing PDFs, but also annotating, editing, and signing documents, all with a polished UI.

The post explored three methods for embedding PDFs in React applications — <iframe>, <embed>, and <object> — which are easy to implement but come with limitations in customization and interactivity. These are great for simple, quick projects, but if you need more advanced features, Nutrient is the solution.

You can also deploy our vanilla JavaScript PDF viewer or use one of our many web framework deployment options like Vue.js, Angular, and jQuery. To see a list of all web frameworks, start your free trial. Or, launch our demo to see our viewer in action.

FAQ

How can I create a PDF viewer in React.js using react-pdf? You can create a PDF viewer in React.js by installing the react-pdf library, importing its components, and using the Document and Page components to render PDF files.
What are the main components of the react-pdf library? The main components are:
  • Document — Used for loading the PDF file.
  • Page — Used for rendering individual pages of the PDF.
These components leverage the PDF.js library to display PDF content.
How do I install and set up react-pdf in a React project? Install react-pdf using npm with the following command:
npm install @react-pdf-viewer/react-pdf
Then, set up your project by:
  1. Importing the necessary components from the library.
  2. Configuring the PDF.js worker file to ensure proper rendering.
  3. Using the Document and Page components to display your PDF.
What are the limitations of the react-pdf library? Some limitations of react-pdf include:
  • It lacks a built-in user interface for navigation or other controls.
  • Text selection can sometimes be inconsistent.
  • Users need to manually build features like zoom, search, and navigation controls.
How can I enhance the functionality of a React.js PDF viewer? You can enhance the functionality by:
  • Building custom UI controls such as navigation, zoom, and search functionality.
  • Integrating libraries like Nutrient to add advanced features like annotations, form filling, and enhanced user interface components.
Author
Hulya Masharipov
Hulya Masharipov Technical Writer

Hulya is a frontend web developer and technical writer at Nutrient who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

Free trial Ready to get started?
Free trial