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.
How to build a React PDF viewer using react-pdf

Before diving into react-pdf(opens in a new tab) 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 advanced PDF features — 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 user interface (UI) controls, the easiest way to embed PDFs in your React app is by using native HTML tags such as <iframe>, <embed>, and <object>. These methods require no additional libraries and are quick to set up — ideal for basic PDF viewing.

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

✘ No custom navigation or annotations

✘ Limited interactivity (e.g. no built-in text selection or zoom control)

Alternatives: embed and object

While <iframe> is the most common choice, <embed> and <object> offer similar capabilities with slight differences:

  • <embed> — Slightly more lightweight than <iframe>, but lacks fallback support for older browsers.
  • <object> — Offers better fallback handling (e.g. showing a download link if PDF rendering fails), and can embed other media types too, but is a bit more complex to implement.

You can explore sample implementations for these tags here.

Comparison of embedding methods

MethodEase of useCustomizationFallback supportBrowser compatibility
<iframe>⭐⭐⭐⭐✅ Excellent
<embed>⭐⭐⭐⭐✅ Good
<object>⭐⭐⭐⭐⭐✅ Excellent

When to use these methods

Use native HTML embedding methods when:

  • You just need to display PDFs — no navigation, search, or interactivity required.
  • You want a quick prototype without installing extra libraries.
  • You’re building a lightweight application that minimizes dependencies.

However, these options fall short for projects needing advanced PDF controls, annotations, or a custom UI. For those, libraries like react-pdf or commercial SDKs like Nutrient offer much more flexibility and power.

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.

Comparing React PDF libraries: react-pdf vs @react-pdf/renderer

When choosing a PDF library for your React app, two popular open source options stand out.

@react-pdf/renderer

@react-pdf/renderer(opens in a new tab):

  • Use case — Generating PDFs dynamically from React components (e.g. invoices, reports).
  • Downloads — ~510K weekly downloads on npm.
  • Guide — Check out our how to create a PDF with React.js tutorial.

react-pdf

react-pdf(opens in a new tab):

  • Use case — Displaying existing PDFs within React applications.
  • Downloads — ~950K weekly downloads on npm.
  • Why use it?
    • Easy integration with React projects
    • Fully customizable UI using Document and Page components
    • Compatible with hooks and context
    • Backed by an active developer community

Keep in mind: You’ll need to build the user interface from scratch and handle performance optimizations for large documents.

The next section covers prerequisites for setting up your PDF viewer.

Requirements to get started

To get started, you’ll need:

You’ll also use Vite(opens in a new tab) to quickly scaffold your React project.

Building a React.js PDF viewer with react-pdf

Start by creating a React.js project with vite(opens in a new tab):

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

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

Terminal window
cd react-pdf-demo

Adding react-pdf

  1. Now, you can install the npm package for the react-pdf library from the terminal:
Terminal window
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="document.pdf" // Path to your PDF file.
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();
// The rest of the code.

You can read more about how to configure a PDF.js worker in your project here(opens in a new tab).

  1. Now, start the application by running the following:
Terminal window
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.

You can access the full code on GitHub(opens in a new tab).

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.

Setting up Nutrient Web SDK in a React + Vite project

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.

Creating a new React project

Use vite(opens in a new tab) to scaffold out a simple React application:

Terminal window
npm create vite@latest nutrient-react-example -- --template react
cd nutrient-react-example

Install Nutrient Web SDK

Next, install the @nutrient-sdk/viewer package:

Terminal window
npm i @nutrient-sdk/viewer

Copying SDK assets to the public directory

Nutrient Web SDK loads its WebAssembly and supporting files from a local path, so you need to copy them to the public folder. Start by installing the required copy plugin:

Terminal window
npm install -D rollup-plugin-copy

Then, update your Vite config (vite.config.ts) to copy the SDK’s asset files during build:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import copy from 'rollup-plugin-copy';
export default defineConfig({
plugins: [
copy({
targets: [
{
src:
'node_modules/@nutrient-sdk/viewer/dist/nutrient-viewer-lib',
dest: 'public/',
},
],
hook: 'buildStart',
}),
react(),
],
});

Displaying a PDF

Now that everything is set up, you’ll render a PDF using the Nutrient SDK.

Basic usage in App.tsx:

import { useEffect, useRef } from 'react';
function App() {
const containerRef = useRef(null);
useEffect(() => {
const container = containerRef.current;
let cleanup = () => {};
(async () => {
const NutrientViewer = (await import('@nutrient-sdk/viewer'))
.default;
// Unload any previous instance.
NutrientViewer.unload(container);
if (container && NutrientViewer) {
NutrientViewer.load({
container,
document:
'https://www.nutrient.io/downloads/pspdfkit-web-demo.pdf',
baseUrl: `${window.location.protocol}//${
window.location.host
}/${import.meta.env.PUBLIC_URL ?? ''}`,
});
}
cleanup = () => {
NutrientViewer.unload(container);
};
})();
return cleanup;
}, []);
return (
<div
ref={containerRef}
style={{ height: '100vh', width: '100vw' }}
/>
);
}
export default App;

You can also render a different file by changing the document path or making it dynamic.

Once everything is configured, start your app:

Terminal window
npm run dev

You’ll now see the Nutrient Web SDK UI rendering your PDF inside the browser!

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.

You can find the finished code on GitHub(opens in a new tab).

Why Nutrient is the best choice for your React PDF viewer

When it comes to building a production-ready PDF viewer in React, Nutrient stands out with its powerful feature set and ease of use:

Out-of-the-box UI — A polished, responsive interface with built-in toolbars, navigation, zoom, and layout options.

15+ annotation tools — Highlight text, draw shapes, add comments, and more with zero configuration.

Document editing — Modify text, add pages, redact content, and fill forms directly in the browser.

Broad file support — View and edit PDFs, Word, Excel, and image formats like JPG and PNG.

Optimized performance — Fast rendering even for large, multi-page documents.

Commercial-grade reliability — Backed by dedicated technical support and frequent updates.

If you’re looking for an all-in-one PDF solution with advanced capabilities, Nutrient lets you deliver a rich document experience without building everything from scratch.

Comparing react-pdf and Nutrient SDK

Here’s a quick side-by-side comparison to help you decide which solution fits your needs best:

Featurereact-pdfNutrient SDK
Out-of-the-box UI❌ No✅ Yes — prebuilt, customizable
Annotation tools❌ Manual implementation✅ 15+ built-in tools
Form filling❌ Not supported✅ Fully supported
Text selection❌ Limited and inconsistent✅ Optimized for precision and usability
File format supportPDF onlyPDF, DOCX, XLSX, JPG, PNG, etc.
LicensingMIT LicenseCommercial license required
Performance on large filesMay lagOptimized rendering with WebAssembly

Accessibility considerations

When choosing how to embed or render PDFs in your React app, it’s important to consider accessibility:

  • <iframe>, <embed>, <object> — Minimal accessibility support. PDFs embedded this way are often not accessible to screen readers or keyboard users.
  • react-pdf — Basic ARIA and keyboard navigation can be added manually, but text layers are often inaccessible out of the box.
  • Nutrient SDK: —Offers better support for accessible navigation, keyboard interaction, and screen reader compatibility. Text layers, tab focus, and annotations are optimized for accessibility out of the box.

For accessibility compliance (e.g. WCAG or Section 508), Nutrient is the more robust solution.

Conclusion

In this blog post, you learned how to build a React.js PDF viewer using the react-pdf(opens in a new tab) 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.

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?

react-pdf doesn’t include built-in UI components and may have limitations with text selection or performance on large files. Read the full list of limitations.

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.
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.

Explore related topics

FREE TRIAL Ready to get started?