Library / SDK
mikecousins/react-pdf-js avatar
mikecousins/react-pdf-js

react-pdf-js renders PDFs in React through a usePdf hook

A React component to wrap PDF.js

807 stars151 forksTypeScriptMIT

At a glance

What is it?
react-pdf-js is a TypeScript React component that renders PDF.js output onto a canvas and hands back PDFDocumentProxy and PDFPageProxy objects, aimed at teams that want PDF rendering without hand-writing the PDF.js lifecycle.
Who is it for?
Use react-pdf-js when your React app needs to display PDF pages on a canvas and you would rather not wire the PDF.js loading, page and render lifecycle by hand. Do not reach for it if you need selectable text, annotation layers, server side rendering or PDF forms, because the documentation describes none of those.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 73 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why wrap PDF.js rather than call it directly

PDF.js is a large library with an imperative lifecycle: you load a document, wait for a page, size a viewport, render into a canvas and clean up afterwards. Doing that inside React means translating several asynchronous stages into state updates and effects. react-pdf-js exists to absorb that translation. It is a React component to wrap PDF.js, published under the package name @mikecousins/react-pdf, and it targets the case where an application already speaks React and needs a document viewer without a separate framework. The interesting design decision is what it does not render for you. The component draws pages onto a canvas element that you own and pass in as a ref, which means pixel output comes from PDF.js while everything around the viewer, the toolbar, the pagination controls and the surrounding layout, stays ordinary React. That split makes it easy to restyle a viewer, and it also means the package is not a ready made drop in widget.

The usePdf hook returns PDF.js proxies instead of hiding them

The core of the API is a single hook, usePdf, called with an options object. It returns two values, pdfDocument and pdfPage, which are described as PDF.js's PDFDocumentProxy and PDFPageProxy objects. Both can be undefined if the document or the page has not been loaded yet, which is the mechanism you use to render a loading state. The returned objects are the same objects PDF.js itself exposes, so any capability available on the underlying proxies is still reachable through the hook rather than hidden behind a bespoke abstraction. The hook takes the page number and a canvas ref, and returns the current document and page for that combination. A minimal integration therefore looks like this:

js
import React, { useState, useRef } from 'react';
import { usePdf } from '@mikecousins/react-pdf';

The canvas reference is created with useRef and rendered as a plain canvas element, and the same ref is handed to the hook:

js
const canvasRef = useRef(null);
js
<canvas ref={canvasRef} />

The hook is then called with the file, the current page and that reference:

js
const { pdfDocument, pdfPage } = usePdf({
  file: 'test.pdf',
  page,
  canvasRef,
});

The README example goes one step further and builds a pager around the returned document, disabling the Previous button on the first page and the Next button once the current page equals pdfDocument.numPages, which is the natural way to consume numPages.

Installing the package and wiring a canvas

Installation pulls in two packages, the wrapper and PDF.js itself, because the wrapper does not bundle the rendering engine:

bash
yarn add @mikecousins/react-pdf pdfjs-dist

The npm spelling is equally short:

bash
npm install @mikecousins/react-pdf pdfjs-dist

Both commands place the wrapper and the renderer side by side in your dependency tree, which matters because the wrapper reaches into the installed copy of pdfjs-dist for the character maps it needs by default. A live demo of the component is hosted at https://react-pdf.cousins.ai, and the package can be consumed from a plain bundler setup or from the tsup and vite toolchain listed among the repository topics.

Props for the worker, character maps, credentials and geometry

The option set covers the parts of PDF.js that applications most often need to override. page selects the page to display and defaults to 1. scale scales the PDF and defaults to 1. rotate turns it by a number of degrees and defaults to 0. cMapUrl specifies a cmap url, defaulting to a path inside node_modules for pdfjs-dist, and cMapPacked states whether the cmaps are packed, defaulting to false. workerSrc points at a custom pdf worker url, and the default is a cdnjs.cloudflare.com path with the pdf.js version interpolated into it, which is a decision worth reviewing if your application runs a strict content security policy or avoids third party origins. withCredentials adds the same flag to the request for the document and defaults to false. The file option is the URL of the PDF file, and the documentation shows it used with a remote address. Because the worker default is a public CDN, a deployment that must keep all traffic inside its own network has to override workerSrc explicitly.

Six callbacks carry every load and render outcome

Error handling is delegated rather than thrown, and the documentation is explicit about which callback fires when. onDocumentLoadSuccess is called when the PDF document data is fully loaded, with the PDFDocumentProxy as its only argument. onDocumentLoadFail is called after an error occurs during document data loading. onPageLoadSuccess fires when the page data is fully loaded, with the PDFPageProxy as its only argument, and onPageLoadFail fires after an error during page data loading. Rendering has its own pair: onPageRenderSuccess is called when the page has been fully rendered into the DOM, again with the PDFPageProxy as the only argument, and onPageRenderFail is called after an error occurred during page rendering. Splitting load failures from render failures is useful, since a network or document error and a canvas problem need different responses. What the documentation does not say is what happens when no callback is supplied, so an application that wants reliable error reporting should register the failure handlers rather than rely on default behaviour.

A pnpm and turbo monorepo behind a single published package

The repository is larger than the README suggests, and the layout tells you how releases are managed. The root package.json is a private workspace root named react-pdf-js-mono with workspaces for apps and packages, a packageManager field pinning [email protected], and turbo as the task runner. The scripts are thin wrappers around turbo: build runs turbo run build, test runs turbo run test, typecheck runs turbo run test's sibling task, and lint calls oxlint while format calls oxfmt. Releases go through changesets, with separate changeset, changeset:version and changeset:publish scripts, so version bumps are driven by declared changesets rather than by hand. The published package and the repository are not the same version line: the npm package @mikecousins/react-pdf was at 8.1.2 on 2026-05-22 while the workspace root was at 5.5.1, and an earlier tag of v7.0.2 dates from 2024-01-16. The last push to the repository was on 2026-08-12. The project is MIT licensed.

A canvas-only viewer with no documented text layer or server side story

Several gaps are worth naming before you commit to this approach. First, output is canvas based. Nothing in the README describes text layer rendering, annotation handling, form filling or document outlines, so if a user needs to select and copy text from a PDF or fill a form, this package does not describe a path to it. Second, the hook depends on a canvas element and on client side loading of the document, and the documentation does not discuss server side rendering, so a Next.js style setup that renders on the server needs its own handling that you will have to design. Third, the default worker lives on a third party CDN and the default cmap url points into node_modules, which means your build output and network policy both need to accommodate those two locations. Fourth, the API surface is small and stable, but it tracks PDF.js: the proxy objects handed back are PDF.js types, so a PDF.js upgrade can change types your own code depends on. Given a small surface, the wrapper stays easy to replace with direct PDF.js calls if the wrapper falls behind.

Editorial conclusion

Use react-pdf-js when your React app needs to display PDF pages on a canvas and you would rather not wire the PDF.js loading, page and render lifecycle by hand. Do not reach for it if you need selectable text, annotation layers, server side rendering or PDF forms, because the documentation describes none of those. Before shipping, check that the default workerSrc pointing at cdnjs.cloudflare.com matches your content security policy, pin the pdfjs-dist version that matches the PDF.js release you target, and review the MIT licence terms for your distribution model.

Frequently asked questions

How do I install react-pdf-js and PDF.js together?

The README gives the install command as yarn add @mikecousins/react-pdf pdfjs-dist, or the npm equivalent npm install @mikecousins/react-pdf pdfjs-dist. Both packages are needed because the wrapper does not bundle the rendering engine.

What does the usePdf hook return in react-pdf-js?

It returns pdfDocument and pdfPage, which are PDF.js PDFDocumentProxy and PDFPageProxy objects. Either can be undefined while the document or the page is still loading, so you can drive a loading indicator from those values.

How do I show errors when a PDF fails to load or render in react-pdf-js?

The hook accepts separate failure callbacks: onDocumentLoadFail and onPageLoadFail for loading problems, and onPageRenderFail for problems during rendering, with onDocumentLoadSuccess, onPageLoadSuccess and onPageRenderSuccess reporting the successful counterparts.

Can react-pdf-js use its own PDF worker instead of a CDN?

Yes. The workerSrc option takes a custom pdf worker url, and the default value points at cdnjs.cloudflare.com with the pdf.js version interpolated, so a deployment that avoids third party origins has to override workerSrc.

Official sources

  1. License: MIT
  2. mikecousins/react-pdf-js on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mikecousins-react-pdf-js.svg)](https://hysenlabs.com/projects/mikecousins-react-pdf-js)

Was this useful?