Open a PDF in React on the Web

In a previous article, I discussed simple options for opening a PDF in your web app without JavaScript, along with how to render PDF files in the browser with PDF.js. Today, I’m going one step further and will examine how we can open a PDF in a React application on the web.

React is a popular JavaScript library for building user interfaces on the web as well as a multitude of other systems, including iOS and Android. In this article, we’ll use react-dom and focus on the web. If you’re looking for a React Native guide, we’ve also got you covered.

Getting Started

For this article, we’ll be using a library by Wojciech Maj called react-pdf. If you use your favorite online search engine, you’ll likely find another library with the same name, created by Diego Muracciole. However, at the time of writing, the latter is only used to create PDFs.

react-pdf gives us a React-based component API for opening PDF files and rendering them using PDF.js.

To get started, we’ll set up a minimal React application using Create React App. This allows us to get started without having to think about configuration (alternatively, you can take a look at the fantastic React documentation and learn about ways to get started without using any additional tooling). To do this, we simply run the following:

1
2
3
yarn create react-app pdf-app
cd pdf-app
yarn start
1
2
3
npx create-react-app pdf-app
cd pdf-app
npm start

After these commands are run, your favorite browser should open, and you should see the boilerplate generated by Create React App.

Rendering a PDF

To start rendering our first PDF, we begin by placing the file we want to render inside the ./public directory of the pdf-app folder. This ensures we can access the file from the web.

Next, we add react-pdf to our project:

1
yarn add react-pdf
1
npm install react-pdf

react-pdf comes with two components that are of interest when rendering a PDF: Document and Page. Document is used to open a PDF and is a mandatory part. Within the document, we can mount pages, which are used to render the PDF page. To integrate this into our example project, we’re going to open ./src/App.js and replace its contents with the following:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { Component } from "react";
import { Document, Page } from "react-pdf";

export default class App extends Component {
  state = { numPages: null, pageNumber: 1 };

  onDocumentLoadSuccess = ({ numPages }) => {
    this.setState({ numPages });
  };

  goToPrevPage = () =>
    this.setState(state => ({ pageNumber: state.pageNumber - 1 }));
  goToNextPage = () =>
    this.setState(state => ({ pageNumber: state.pageNumber + 1 }));

  render() {
    const { pageNumber, numPages } = this.state;

    return (
      <div>
        <nav>
          <button onClick={this.goToPrevPage}>Prev</button>
          <button onClick={this.goToNextPage}>Next</button>
        </nav>

        <div style={{ width: 600 }}>
          <Document
            file="/example.pdf"
            onLoadSuccess={this.onDocumentLoadSuccess}
          >
            <Page pageNumber={pageNumber} width={600} />
          </Document>
        </div>

        <p>
          Page {pageNumber} of {numPages}
        </p>
      </div>
    );
  }
}

This is already enough to render a PDF in React.

Since react-pdf does not come with a user interface, we have built our own. In the example above, we render two buttons to navigate the page within the <nav> elements and show the total progress on the bottom. The result looks something like this:

Advanced Features

By default, react-pdf enables important features of PDF.js — including the text layer, which allows us to copy and paste text from the PDF. However, one feature that is disabled is the dedicated annotation layer. In a PDF, annotations provide additional information and enable the use of hyperlinks. In our example PDF, we have a hyperlink on the first page that we want to enable as well. To do this, we have to import an additional file for the CSS that is needed:

1
import "react-pdf/dist/Page/AnnotationLayer.css";
Screenshot of a PDF page with a link annotation

Another improvement we can make is to use web workers so that our PDFs can be rendered in another thread, in order to keep our main window responsive at all times. Luckily, react-pdf comes with pre-built support for adding this option to Webpack, and Create React App uses Webpack under the hood.

To enable web workers, all we need to do is replace our input line with the following:

Copy
1
2
3
4
import React, { Component } from "react";
- import { Document, Page } from "react-pdf";
+ import { Document, Page } from "react-pdf/dist/entry.webpack";
import "react-pdf/dist/Page/AnnotationLayer.css";

You can see the worker in action by inspecting the page with your favorite developer tools.

Screenshot of Chrome DevTools showing the web worker in action

Conclusion

With just a few lines of code, we were able to utilize the full power of PDF.js in a React application. This is a great way to get started and will certainly help boost your business.

We’ve already discussed the underlying technology in great detail in the previous post. I suggest that you look through that to get an understanding of the pros and cons when working with PDF.js.

If you’re looking for a solution that includes a fully responsive and customizable user interface, support for various annotation types, interactive forms and signatures, mobile support, persistence management, and many more features, we have a solution for you. We at PSPDFKit work on the next generation of PDF viewers for the web. Together with PSPDFKit Instant, we offer an enterprise-ready PDF solution for web browsers and other platforms, along with industry-leading first-class support included with every plan. Click here to see PSPDFKit for Web in action and check out our blog post and example application to learn more.

PSPDFKit for Web

PDF viewing, annotating, and collaboration for web apps.

Try Now