For most React apps, use react-pdf: it wraps PDF.js in React’s Document and Page components. Configure its PDF.js worker in the same module as those components, then render the pages you need. If you need lower-level control over canvas rendering, use pdfjs-dist directly. In either case, the worker must be available to the browser and match the installed PDF.js version.
Choose the right PDF.js layer for your React app
PDF.js has three layers: a core layer that parses and interprets PDF data, a display layer that exposes APIs for rendering and document information, and a viewer layer that provides a user interface built on the display layer. Most React integrations use the display layer, either directly through pdfjs-dist or through the React-PDF wrapper.
- Choose React-PDF when you want React components for loading a document and displaying pages, with callbacks and React-oriented loading and error patterns.
- Choose
pdfjs-distdirectly when you want to manage loading, page state, canvas sizing, and rendering yourself. - Build on the viewer layer only when its interface is a useful starting point. Mozilla describes the viewer as a UI built on the display layer and asks developers to reskin or build upon it rather than copy the embedded viewer unchanged.
The examples below use the browser-side display API. They assume the PDF can be fetched by the app; serving the file, handling cross-origin access, and authorizing access to it are separate concerns from drawing its pages.
Install and configure React-PDF
Check the package’s current requirements
Install React-PDF with:
npm install react-pdf
The React-PDF README describes its 11.x branch as requiring React 19 or later and Node.js 22.13.0 or later. It lists current major browsers with minimums of Chrome 125 and Safari 18, including iOS 18. These requirements can change, so check the README for the version you intend to install before upgrading an existing app or choosing a deployment target.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →#1 Best Overall
Set the worker in the component module
React-PDF uses PDF.js under the hood. The browser worker performs PDF processing separately from the UI thread, so the app must make a compatible worker file available. For a bundler setup that supports import.meta.url, configure it in the same module that imports and renders Document or Page:
import { pdfjs, Document, Page } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
Keep this assignment alongside the React-PDF imports and component. React-PDF warns that placing the assignment in a separate module can allow module execution order to overwrite the custom workerSrc. A missing or incompatible worker is a common cause of the “fake worker” or worker-loading errors people encounter when setting up PDF.js.
Render a page with React-PDF
This component tracks the total page count after the document loads and lets the user move between pages:
import { useState } from 'react';
import { pdfjs, Document, Page } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
export default function PdfViewer() {
const [numPages, setNumPages] = useState<number>();
const [pageNumber, setPageNumber] = useState(1);
return (
<section>
<Document
file="/somefile.pdf"
onLoadSuccess={({ numPages }) => setNumPages(numPages)}
>
<Page pageNumber={pageNumber} />
</Document>
<p>Page {pageNumber} of {numPages ?? '…'}</p>
<button
type="button"
disabled={pageNumber <= 1}
onClick={() => setPageNumber(page => page - 1)}
>
Previous
</button>
<button
type="button"
disabled={!numPages || pageNumber >= numPages}
onClick={() => setPageNumber(page => page + 1)}
>
Next
</button>
</section>
);
}
Replace /somefile.pdf with the path or URL your app uses. The example renders one page at a time; it does not create a complete multi-page document viewer with navigation, zoom, or search. Add those controls if your use case needs them. React-PDF’s maintained example also demonstrates wrapping the document and page in Suspense and an Error Boundary; use those patterns when they fit your app’s loading and error-handling design.
Free tools Windows power users keep installed
One-click scans. No signup required.
Configure workers for your build
The new URL(..., import.meta.url) pattern is a convenient bundler setup, but it is not the only documented option. Choose a worker delivery method that fits your build and keep the worker version matched to the pdfjs-dist version used by React-PDF.
- Bundle it: use the
new URLpattern shown above when your bundler supports it. - Copy it into the output: React-PDF documents copying
pdf.worker.mjsinto the build output and pointingworkerSrcat the resulting URL. - Use a version-matched CDN: React-PDF documents a URL pattern based on
pdfjs.version://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs. This avoids hard-coding a separate version, but the browser must be able to reach the CDN. - Support older browsers: React-PDF documents replacing
/build/with/legacy/build/for the legacy worker. That worker alone does not guarantee compatibility: polyfills and bundler transpilation may also be necessary.
For direct pdfjs-dist use with Webpack, Mozilla’s setup guidance says to bundle the worker separately; its pdfjs-dist/webpack entry can provide autoconfiguration. For other bundlers, follow that bundler’s handling of worker assets and verify that the emitted worker URL is reachable in the deployed app, not only in development.
Rank #3
Render with pdfjs-dist directly
Use the display API directly when the React-PDF component model does not give you the control you need. The minimal lifecycle is: configure the worker, load the document, request a page, calculate its viewport, size a canvas, render, and await the render task.
import * as pdfjsLib from 'pdfjs-dist';
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
export async function renderPdfPage(pdfPath, canvas, pageNumber = 1) {
const context = canvas.getContext('2d');
if (!context) {
throw new Error('Could not create a 2D canvas context');
}
const loadingTask = pdfjsLib.getDocument(pdfPath);
const pdfDocument = await loadingTask.promise;
const pdfPage = await pdfDocument.getPage(pageNumber);
const viewport = pdfPage.getViewport({ scale: 1.0 });
canvas.width = viewport.width;
canvas.height = viewport.height;
const renderTask = pdfPage.render({
canvasContext: context,
viewport,
});
await renderTask.promise;
return { numPages: pdfDocument.numPages, pageNumber };
}
Call it after the canvas exists in the DOM, for example from a React effect. If a component can unmount or start another render while loading, add cleanup and cancellation handling appropriate to your app so an old task does not race a newer one. The example uses scale 1.0 for a straightforward viewport; choose a different scale if you need a larger or smaller rendered page and size the canvas from that viewport.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPackage assets for text, annotations, and special PDFs
A page can render while optional layers or characters are missing if supporting assets or styles are absent. Add only the assets your PDFs and interface require.
Rank #4
- Links and annotations: import
react-pdf/dist/Page/AnnotationLayer.csswhen annotation elements such as links should display correctly. - Selectable text: import
react-pdf/dist/Page/TextLayer.csswhen using the text layer. A canvas image alone is not selectable text. - Non-Latin characters: copy
pdfjs-dist/cmapsinto a served location or serve them from a CDN, then provide a stable options object such as{ cMapUrl: '/cmaps/' }toDocument. - JPEG 2000 content: PDFs that use JPEG 2000 may require the
wasmdirectory and awasmUrloption. - Standard fonts: PDFs that rely on standard fonts may require the
standard_fontsdirectory and astandardFontDataUrloption.
Keep React-PDF’s options object outside the component or memoize it. Creating a new object on every render can make React-PDF treat the options as changed repeatedly.
Run the app over HTTP
Do not open the React app as a local file:// page. Mozilla’s guidance is explicit: the PDF.js worker is not enabled for file:// URLs, so use a server. Run the app through its development server while building, and serve the built app over HTTP in deployment. This also gives the worker and PDF files browser-accessible URLs rather than local file paths.
Troubleshoot common React PDF.js errors
Worker failed to load, or PDF.js fell back to a fake worker
- Likely cause:
workerSrcis unset, points to a URL that is not emitted or served, or uses a worker version that differs from the installed PDF.js package. - Fix: configure the worker beside the React-PDF imports; check the browser Network panel for the worker request; verify the deployed URL and ensure the worker comes from the same
pdfjs-distversion.
The app was opened from a file path
- Likely cause: the page uses a
file://URL, where the worker is not enabled. - Fix: start an HTTP development server and access the app through its served URL.
Text or links are missing even though the page image appears
- Likely cause: the text or annotation layer styles are missing, or the relevant layer is not enabled.
- Fix: import
TextLayer.cssfor selectable text andAnnotationLayer.cssfor annotations such as links, then verify the layer configuration in the component.
Some characters appear as boxes or do not render
- Likely cause: required character maps or standard font data are unavailable to PDF.js.
- Fix: serve the cMaps or standard font assets and configure their URLs through the relevant options. Keep the options object stable between React renders.
A PDF with JPEG 2000 images fails or renders incompletely
- Likely cause: the required PDF.js WASM assets are not included in the deployed output.
- Fix: package and serve the
wasmdirectory, then setwasmUrlas required by the React-PDF setup.
The canvas is blank or too small
- Likely cause: rendering was not awaited, the canvas has not mounted, or its dimensions do not match the page viewport.
- Fix: in direct rendering, get the page viewport, set the canvas width and height from it, and await
renderTask.promise. In React-PDF, confirm that the document loaded and that the requested page number is valid.
Or skip the browser setup
If your goal is to capture a URL as an image or PDF rather than build an interactive PDF reader into your React app, ScreenshotNeo is a website screenshot API and MCP server. It is not a replacement for PDF.js page rendering inside React; it captures a web URL. A one-call image example is:
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for the free plan.
Performance and reliability considerations
Both approaches depend on loading a PDF, processing the requested page, and delivering a matching worker and any required auxiliary assets. React-PDF handles the component integration; direct pdfjs-dist leaves more lifecycle and canvas work to your application. For a multi-page document, rendering only the pages currently needed avoids asking the browser to draw every page at once. For either approach, verify the production build’s worker and asset URLs and test representative PDFs, especially those that use non-Latin text, annotations, JPEG 2000, or standard fonts.
Do not treat a successful local development render as proof that production is configured: a worker or asset that the dev server resolves may be missing from the deployed output. Check failed network requests and the browser console when diagnosing a deployment-only problem.
FAQ
Can I display a PDF without React-PDF?
Yes. Install pdfjs-dist and use its display API to load the document and render pages to a canvas. You will manage the loading, canvas, page state, worker, and errors yourself.
Does PDF.js provide a complete reader interface?
The viewer layer supplies a UI, but the React-PDF examples here focus on rendering pages. A production reader may also need its own navigation, zoom, loading and error UI, and accessibility decisions.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

