-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Upgrade guide from version 10.x to 11.x
React-PDF 11 updates PDF.js from 5.4.296 to 6.3.289 and enables React Suspense and Error Boundaries by default. For the previous API, see the React-PDF 10.x documentation.
Upgrade react and react-dom to version 19 or later, along with @types/react and @types/react-dom if you use TypeScript. Support for React 16.8, 17, and 18 has been dropped.
Preact users need a preact/compat version with React's use API.
Document, Page, Thumbnail, and Outline now suspend while loading and send failures to the nearest Error Boundary. Move your loading and error UI into boundary fallbacks:
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Document, Page } from 'react-pdf';
<ErrorBoundary fallback={<p>Could not load PDF.</p>}>
<Suspense fallback={<p>Loading PDF…</p>}>
<Document file={file}>
<Page pageNumber={1} />
</Document>
</Suspense>
</ErrorBoundary>;Install react-error-boundary for this example, or use your application's existing Error Boundary. No React-PDF provider is needed.
Suspense waits for document, page, or outline data. Canvas, text, annotations, and the structure tree still render progressively; their failures also reach the Error Boundary. noData continues to handle empty input.
Set suspense={false} to continue using the loading and error props:
<Document error="Could not load PDF." file={file} loading="Loading PDF…" suspense={false}>
<Page pageNumber={1} />
</Document>Children inherit the document's setting and can override it. Set suspense={false} explicitly on standalone Page, Thumbnail, or Outline components if needed.
Load callbacks remain available, but success callbacks run after the consuming component commits. Keep password and progress UI outside the suspended viewer.
Suspense compares plain file/options objects by value. Keep binary inputs, workers, and range transports outside the suspended subtree. Concurrent initial loads may share password/progress handlers, and superseded loads may still call them. Do not rely on unmounting a viewer to immediately stop these callbacks.
Use startTransition when changing the file or page to keep previously revealed content visible while the new data loads:
import { startTransition } from 'react';
function changePage(pageNumber: number) {
startTransition(() => {
setPageNumber(pageNumber);
});
}Here, setPageNumber updates state in a component outside the suspended viewer. Suspense waits for page data; it does not wait for the canvas to finish painting.
Place the Error Boundary around Document so resetting it retries the entire load:
<ErrorBoundary
fallbackRender={({ resetErrorBoundary }) => (
<button onClick={resetErrorBoundary}>Retry</button>
)}
>
<Suspense fallback={<p>Loading PDF…</p>}>
<Document file={file}>
<Page pageNumber={1} />
</Document>
</Suspense>
</ErrorBoundary>;To reload a mounted document explicitly, change its React key.
React-PDF supports the latest versions of all major modern browsers.
Minimum browser requirements are Chrome 125 and Safari 18 (iOS 18). Versions below the latest releases, but meeting these minimums, may require additional polyfills, bundler transpilation, and the legacy PDF.js worker.
React-PDF requires Node.js 22.13.0 or newer.
See the browser compatibility changes and PDF.js package requirements.
If you copy the PDF.js worker, cMaps, standard fonts, or wasm files into your application, copy them again from the updated pdfjs-dist package. The worker version must match the PDF.js version used by React-PDF.
If you configure a worker through a CDN, use pdfjs.version instead of a hardcoded version:
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;Set this in the same module where you use <Document> and <Page>. If you also depend on pdfjs-dist directly, keep its version aligned with React-PDF's dependency.
If you call pdfjs.getDocument yourself, wrap URLs in { url } and binary data in { data }:
- const loadingTask = pdfjs.getDocument('/example.pdf');
+ const loadingTask = pdfjs.getDocument({ url: '/example.pdf' });- const loadingTask = pdfjs.getDocument(arrayBuffer);
+ const loadingTask = pdfjs.getDocument({ data: arrayBuffer });No action is required for React-PDF's file prop. For example, <Document file="/example.pdf" /> still works.
If you load and manage PDF.js documents yourself, destroy the loading task instead:
- await pdf.destroy();
+ await pdf.loadingTask.destroy();You can also retain the task returned by pdfjs.getDocument and call loadingTask.destroy() directly. React-PDF handles cleanup for documents it loads, so you do not need to add this to onLoadSuccess or your component's cleanup.
See the PDF.js API removal.
If you use document or page proxies received through React-PDF callbacks, update any code that reads these results:
| API | New result |
|---|---|
pdf.getDestinations() |
Map |
pdf.getAttachments() |
Map or null
|
pdf.getViewerPreferences() |
Map or null
|
pdf.getOpenAction() |
Map or null
|
pdf.getJSActions() / page.getJSActions()
|
Map or null
|
pdf.getFieldObjects() |
Map or null
|
pdf.getMarkInfo() |
Map or null
|
pdf.getPermissions() |
Set or null
|
Use .get() for map lookups and .has() to check permissions:
const destinations = await pdf.getDestinations();
- const destination = destinations['Chapter1'];
+ const destination = destinations.get('Chapter1'); const permissions = await pdf.getPermissions();
- const canPrint = permissions?.includes(pdfjs.PermissionFlag.PRINT);
+ const canPrint = permissions?.has(pdfjs.PermissionFlag.PRINT);For iteration, replace Object.entries(result) with result.entries(). Custom document information returned as info.Custom by pdf.getMetadata() is also a Map when present; the outer info object is unchanged.
In pdfjs-dist 6.3.289, the TypeScript declaration for getMarkInfo() still describes an object, although the runtime returns a Map. TypeScript users accessing these flags should account for this upstream declaration mismatch.
See the 6.1, 6.2, and 6.3 release notes for these API changes.
If you pass CMapReaderFactory, StandardFontDataFactory, or WasmFactory through <Document options={...}> or directly to pdfjs.getDocument, replace those custom implementations with a single BinaryDataFactory. Its fetch({ kind, filename }) method handles the different resource types. This requires adapting your factory implementation, not just renaming an option.
The cMapUrl, standardFontDataUrl, and wasmUrl options remain available. No factory migration is needed if you only configure these URLs. As before, custom main-thread fetching requires useWorkerFetch: false.
The length option was also removed from pdfjs.getDocument options; remove it if you supplied it there. The length constructor argument of PDFDataRangeTransport is separate and remains supported.
See the factory changes and removal of the loading option.
onRenderAnnotationLayerSuccess now runs after PDF.js's asynchronous annotation rendering completes. Rendering failures are reported through onRenderAnnotationLayerError. If you access rendered annotation elements, do so in the success callback instead of assuming they are available immediately after rendering <Page>.