mrkeyoor.com_
Wed 23 Sept 00:32 UTC
npmWeb Frontendupdated 22 Sept 2026

react-pdf review

React-PDF 10.5.0 displays existing PDF files inside React through `Document`, `Page`, `Thumbnail`, and `Outline` components backed by Mozilla PDF.js. Sources can be URLs, uploaded files, byte arrays, or PDF.js parameter objects. A page can render a canvas, selectable text, and interactive annotations, while your application supplies navigation, zoom controls, virtualization, and error UI. This package does not create PDFs; the similarly named `@react-pdf/renderer` handles that separate task.

Verdict

React-PDF 10.5.0 produced a 125.8 KB gzipped browser bundle in our test, while both bare Node 22.23.2 entry checks failed. Install it for a client-only custom viewer whose team will manage the worker and PDF.js assets; choose a full viewer package when controls and virtualization should arrive together.

We installed it

Lab card: what happened when we installed react-pdfScreenshot of react-pdf documentation
Install✓ · 5.3s16 packages on disk · 77 MB
ImportESM import fails · require() fails · ESM package with exports map
Browser125.8 KBgzipped (424.4 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does react-pdf install cleanly?

Yes. In a fresh container with an empty cache, npm install react-pdf finished in 5 seconds, leaving 16 packages and 77 MB on disk. npm audit reported no known vulnerabilities.

How much does react-pdf add to a browser bundle?

125.8 KB gzipped (424.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does react-pdf work with both ESM and CommonJS?

Neither plain import nor require succeeded in our sandbox, so it needs a bundler or extra setup.

Does react-pdf include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

react-pdf or pdfjs-dist: which should you use?

pdfjs-dist: Choose direct PDF.js when you want full control and will write the React lifecycle yourself. React-PDF 10.5.0 produced a 125.8 KB gzipped browser bundle in our test, while both bare Node 22.23.2 entry checks failed.

When should you not use react-pdf?

You need to generate a PDF. The project README sends that use case to @react-pdf/renderer.

API stability4/5`Document` and `Page` remain the main composition model in 10.x, with `Thumbnail` and `Outline` covering secondary views. The package still supports React 16.8 through 19. Worker paths, PDF.js versions, and props can change at major boundaries, which is why the repository links separate documentation for v6 through v10. Pin the major when copying setup code.
Docs5/5The current README documents worker configuration by bundler, pnpm hoisting, Next.js SSR limits, legacy-browser work, layer CSS, CMaps, WebAssembly, standard fonts, file-source identity, and component props. It begins by separating PDF display from PDF generation. The recipes and sample fill in common UI patterns, though teams still design their own complete viewer.
Maintenance5/5npm serves 10.5.0, GitHub records a push on August 20, 2026, and the unarchived repository has 11,152 stars with 18 open issues and pull requests. Current-major documentation and automated workflows are visible. Regular PDF.js changes create ongoing bundler and browser work, and the repository shows that work is being handled rather than left to old recipes.
Ecosystem5/5npm counted 6,335,171 downloads in the week ending August 24, 2026. Version 10.5.0 accepts React peers from 16.8 through 19 and builds on PDF.js 5.4.296. Recipes cover common bundlers and source forms. The package-name collision with `@react-pdf/renderer` remains a practical discovery problem even though the viewer itself is widely used.

Use it if

  • A React product needs to show an existing PDF while controlling its own viewer chrome and navigation.
  • Pages need selectable text, links, thumbnails, or an outline exposed through React components.
  • The source may be a public URL, authenticated request, browser `File`, or `Uint8Array`.
  • The build can own the PDF.js worker plus CMap, standard-font, and WebAssembly assets required by its documents.
Skip it if

Setup reality

We installed React-PDF 10.5.0 in a clean Node 22 Bookworm sandbox. npm took 5.3 seconds, left 16 packages consuming 77 MB, and reported 0 vulnerabilities across all audit severities. The package declares 8 direct dependencies and 3 peers, with 624 KB unpacked. Its TypeScript declarations are bundled.

The package is ESM and has an exports map, yet both our CommonJS require() check and ESM import check failed under Node 22.23.2. That makes a bare server-side load a bad smoke test for this browser viewer and supports the README's instruction to disable SSR in Next.js. A browser esbuild run succeeded at 424.4 KB minified and 125.8 KB gzipped.

PDF.js still needs a worker URL. The recommended v10 code sets pdfjs.GlobalWorkerOptions.workerSrc with new URL(..., import.meta.url) in the same module that renders Document or Page; a separate bootstrap module can lose the assignment through execution order. pnpm layouts may need pdfjs-dist hoisting, and Parcel uses an npm: URL prefix.

Import the supplied text-layer and annotation-layer CSS when those layers are enabled. Copy version-matched CMaps, standard fonts, and WASM when your PDFs require them, then keep the Document options object stable. Browser CORS applies to remote PDFs, and authenticated source objects should be memoized. Long documents need pagination or visibility-based mounting because every rendered page creates canvas and PDF.js work.

Patterns

Point PDF.js at its worker configure-worker

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

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

Keep this assignment in the component module. Another import order can replace a worker value set in a distant bootstrap file.

Display the first loaded page render-one-page

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

export function Viewer() {
  const [pages, setPages] = useState(0);
  return (
    <Document file='/manual.pdf' onLoadSuccess={({ numPages }) => setPages(numPages)}>
      <Page pageNumber={1} />
      <p>{pages ? `1 of ${pages}` : 'Loading...'}</p>
    </Document>
  );
}

Page numbering begins at 1. Nest `Page` inside `Document` unless an already-loaded PDF object is passed directly.

Mount all pages of a short PDF render-all-pages

const [numPages, setNumPages] = useState(0);

<Document file={file} onLoadSuccess={({ numPages }) => setNumPages(numPages)}>
  {Array.from({ length: numPages }, (_, index) => (
    <Page key={index + 1} pageNumber={index + 1} />
  ))}
</Document>

For long files, paginate or mount only visible pages so dozens of large canvases do not render together.

Load the text and annotation styles enable-text-links

import 'react-pdf/dist/Page/TextLayer.css';
import 'react-pdf/dist/Page/AnnotationLayer.css';

<Page
  pageNumber={pageNumber}
  renderTextLayer
  renderAnnotationLayer
  externalLinkTarget='_blank'
/>

Both layers need their package CSS for correct positioning. External links should keep an appropriate `rel` policy.

Fetch a protected PDF source load-authenticated-url

const source = useMemo(() => ({
  url: 'https://api.example.com/files/report.pdf',
  httpHeaders: { Authorization: `Bearer ${token}` },
  withCredentials: true,
}), [token]);

<Document file={source} />

Memoize object-valued `file` props. The remote origin must allow the browser request and its credentials through CORS.

Preview a browser File load-uploaded-file

const [file, setFile] = useState(null);

<input
  type='file'
  accept='application/pdf'
  onChange={(event) => setFile(event.target.files?.[0] ?? null)}
/>
{file && <Document file={file}><Page pageNumber={1} /></Document>}

A selected `File` is accepted directly. Clear both input and viewer state when the user removes it.

Render bytes returned by an API load-byte-array

const response = await fetch('/api/report');
if (!response.ok) throw new Error(`PDF request failed: ${response.status}`);
const bytes = new Uint8Array(await response.arrayBuffer());
setSource({ data: bytes });

<Document file={source} />

Use `Uint8Array` and keep its wrapper object stable; changing identity can trigger a complete document reload.

Tie page width to its container responsive-page

const [width, setWidth] = useState(600);

<ResizeObserverBox onWidth={setWidth}>
  <Page pageNumber={pageNumber} width={Math.min(width, 900)} />
</ResizeObserverBox>

Supplying both `width` and `scale` multiplies the effective size, while `height` is ignored when width is present.

Publish PDF.js support assets configure-font-assets

const options = {
  cMapUrl: '/pdf-assets/cmaps/',
  standardFontDataUrl: '/pdf-assets/standard_fonts/',
  wasmUrl: '/pdf-assets/wasm/',
};

<Document file={file} options={options} />

Copy directories from the exact installed `pdfjs-dist` version and memoize the options object passed to `Document`.

Request an encrypted document password handle-password

<Document
  file={file}
  onPassword={(callback, reason) => {
    const password = window.prompt(reason === 1 ? 'Password required' : 'Incorrect password, try again');
    callback(password ?? '');
  }}
/>

Always invoke the callback. Replace `window.prompt` with an accessible dialog and a clear retry state.

Build a thumbnail rail render-thumbnails

import { Document, Thumbnail } from 'react-pdf';

<Document file={file} onLoadSuccess={({ numPages }) => setNumPages(numPages)}>
  <div className='thumbnails'>
    {Array.from({ length: numPages }, (_, i) => (
      <button key={i} onClick={() => setPageNumber(i + 1)}>
        <Thumbnail pageNumber={i + 1} width={120} />
      </button>
    ))}
  </div>
</Document>

A thumbnail skips text and annotation layers but still performs PDF rendering for each mounted page.

Separate load and render failures handle-load-errors

<Document
  file={file}
  loading={<p>Loading PDF...</p>}
  error={<p>Could not load this PDF.</p>}
  onLoadError={(error) => reportError(error)}
>
  <Page
    pageNumber={pageNumber}
    onRenderError={(error) => reportError(error)}
  />
</Document>

Document parsing and page canvas rendering fail at different stages, so observability should record both callbacks.

Alternatives

PackageRegistryPick it when
pdfjs-distnpmChoose direct PDF.js when you want full control and will write the React lifecycle yourself.
@react-pdf-viewer/corenpmChoose it for a plugin-based viewer with packaged navigation and controls.
@pdfslick/reactnpmChoose it for a PDF.js React viewer whose scope includes virtualization and more of the shell.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.