mrkeyoor.com_
Sat 08 Aug 20:58 UTC
npmWeb Frontendupdated 08 Aug 2026

react-pdf

React-PDF renders existing PDF documents inside React by wrapping Mozilla PDF.js in Document, Page, Thumbnail, and Outline components. It accepts URLs, files, typed arrays, or PDF.js source objects and can render page canvases plus selectable text and clickable annotation layers. It is a viewer building block, not a complete toolbar and not the similarly named @react-pdf/renderer package used to create PDFs.

Verdict

React-PDF is a good rendering layer when your product owns the viewer experience. Skip it if you expect installation to produce a complete PDF application or if worker and asset plumbing are out of scope.

API stability4/5Document and Page have remained the core model across many releases, and v10 still supports React versions back to 16.8. Major branches have separate README links because worker paths, PDF.js versions, and props do move between majors. The package is stable within a pinned major, but copying setup from a v7 or v9 article into v10 is a realistic way to break the build.
Docs5/5The v10 README documents worker strategies for common bundlers, pnpm hoisting, Next.js SSR, legacy browser handling, CMaps, WebAssembly, standard fonts, layer CSS, and a large prop reference for every component. It also opens by distinguishing display from PDF creation, which prevents the most common package-name mistake.
Maintenance5/5Version 10.4.1 was published on February 25, 2026, and the repository was pushed on August 7, 2026. GitHub shows only 19 open issues and pull requests for a project with 11,138 stars, while CI and current-major documentation are visible in the repository. PDF.js upgrades still create regular compatibility work, but the project is plainly active.
Ecosystem5/5The package recorded 5,782,463 npm downloads in the latest complete week and supports React 16.8 through 19. It builds on Mozilla PDF.js, accepts the source types PDF.js users expect, and has recipes for popular React bundlers and frameworks. The main ecosystem hazard is name confusion with @react-pdf/renderer, not lack of adoption.

Use it if

  • You need to display an existing PDF inside a React interface and control the surrounding navigation yourself
  • You want page canvases, selectable text, links, thumbnails, or a document outline as React components
  • Your PDF source may be a URL, uploaded File, Uint8Array, or authenticated PDF.js request object
  • You can own the PDF.js worker and static asset setup in your bundler
Skip it if

Setup reality

`npm install react-pdf` installs React-PDF and its pinned `pdfjs-dist` dependency; React 16.8 or newer, React DOM, and matching React types are peers. A basic component still fails until PDF.js can locate its worker. The recommended v10 setup assigns `pdfjs.GlobalWorkerOptions.workerSrc` with `new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString()` in the same module that renders Document or Page. A separate bootstrap file is unsafe because module order can overwrite the value. Next.js must load the viewer with SSR disabled. pnpm may need `pdfjs-dist` hoisted through `.npmrc` on older pnpm or `publicHoistPattern` in `pnpm-workspace.yaml` on pnpm 11+. Parcel needs the `npm:` URL prefix. Text and annotation layers each need their supplied CSS import. PDFs with non-Latin characters may require copying `pdfjs-dist/cmaps`; JPEG 2000 can require the `wasm` directory; old standard-font PDFs may require `standard_fonts`. Those paths go into a stable, memoized Document `options` object. Remote PDFs must allow browser CORS and authenticated requests need a memoized source object. Rendering every page of a long PDF at once can consume substantial CPU and canvas memory, so real viewers usually render only visible pages or thumbnails.

Patterns

Configure the PDF.js worker for v10configure-worker

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

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

Put this in the same module that renders Document or Page. A different module can run too early and have its value overwritten.

Load a document and render one pagerender-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 numbers are one-based. Document loads the file; Page must be nested inside it or receive a `pdf` object explicitly.

Render every page after loadrender-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>

This is fine for short files. Long documents need visibility-based rendering or pagination to avoid creating many large canvases at once.

Enable selectable text and annotation linksenable-text-links

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

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

The layers render without useful layout unless both supplied stylesheets are included. External links default to a restrictive rel value.

Load a PDF with request headersload-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 because React-PDF uses identity checks. The remote server must also permit the browser request through CORS.

Preview a PDF selected by the userload-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 browser File can be passed directly. Clear application state when the input is reset so the old document is not left visible.

Render PDF bytes from an API responseload-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} />

Prefer Uint8Array for binary data. Keep the source object stable between renders or the document will be reloaded.

Size a page to its containerresponsive-page

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

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

When both width and height are supplied, height is ignored. Combining width and scale multiplies the requested width.

Configure CMaps, fonts, and JPEG 2000 supportconfigure-font-assets

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

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

Copy the matching directories from the installed `pdfjs-dist` version, and define this options object outside the component or memoize it.

Prompt for a protected PDF passwordhandle-password

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

The callback must be called with a password attempt. Replace `window.prompt` with accessible product UI in a real application.

Build clickable page thumbnailsrender-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>

Thumbnail omits text and annotation layers, which keeps it lighter than Page but still renders PDF content for every mounted item.

Report document and page failureshandle-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 load and Page render are different failure stages. Capture both if telemetry needs to distinguish network, parse, and canvas problems.

Alternatives

PackageRegistryPick it when
pdfjs-distnpmYou want direct PDF.js control and are willing to build the React lifecycle and viewer UI yourself
@react-pdf-viewer/corenpmYou want a plugin-oriented viewer with packaged controls instead of low-level page components
@pdfslick/reactnpmYou want a React viewer built around PDF.js with virtualization and a more complete viewing shell