The most direct way to display an existing PDF in a React application is React-PDF: install the package, configure its PDF.js worker in the same module as your viewer components, and render Document and Page. You must also account for client-only rendering in Next.js, serve the app over HTTP rather than file://, and add loading, error, navigation and accessibility behavior.
Build a working viewer with React-PDF
The current React-PDF README documents the 11.x line. It requires React 19 or later and Node.js 22.13.0 or newer, so check the README for the exact package version your project will install before copying this example.
1. Install the dependency
npm install react-pdf
Yarn projects can use yarn add react-pdf. React-PDF uses PDF.js in the browser, including a separate worker for parsing and rendering PDF data.
2. Configure the PDF.js worker in the viewer module
Set GlobalWorkerOptions.workerSrc in the same module that imports and renders Document and Page. The project documentation warns that configuring it in a separate entry file can be overwritten by module execution order.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
import { useState } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
export function PdfViewer({ file }) {
const [numPages, setNumPages] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
function handleLoadSuccess({ numPages: loadedPages }) {
setNumPages(loadedPages);
setPageNumber(1);
}
return (
<section aria-label="PDF viewer">
<Document
file={file}
onLoadSuccess={handleLoadSuccess}
loading={<p>Loading PDF…</p>}
error={<p role="alert">Unable to load this PDF.</p>}
>
<Page pageNumber={pageNumber} />
</Document>
{numPages && (
<nav aria-label="PDF page navigation">
<button
type="button"
onClick={() => setPageNumber((p) => Math.max(1, p - 1))}
disabled={pageNumber <= 1}
>
Previous
</button>
<span>Page {pageNumber} of {numPages}</span>
<button
type="button"
onClick={() => setPageNumber((p) => Math.min(numPages, p + 1))}
disabled={pageNumber >= numPages}
>
Next
</button>
</nav>
)}
</section>
);
}
Pass a URL, a File, a typed array or another value accepted by the installed React-PDF version as the file prop. For a public document, <PdfViewer file="/manual.pdf" /> is sufficient. For a user-selected file, pass the value from an <input type="file" /> element.
3. Render all pages only when the document is small
To show every page, create a Page for each loaded page:
{Array.from({ length: numPages ?? 0 }, (_, index) => (
<Page key={index + 1} pageNumber={index + 1} />
))}
This is convenient for short documents but can create a large DOM and consume substantial memory for a long PDF. Use one page at a time, pagination, or virtualization for manuals and reports with many pages.
Next.js: keep the viewer on the client
React-PDF’s current guidance says the module that configures the worker and uses the components should skip server-side rendering in Next.js. With the App Router, put the viewer in a client component and dynamically import it with SSR disabled from the route that uses it:
// app/documents/page.jsx
import dynamic from 'next/dynamic';
const PdfViewer = dynamic(() => import('../../components/PdfViewer'), {
ssr: false,
loading: () => <p>Preparing PDF viewer…</p>,
});
export default function DocumentsPage() {
return <PdfViewer file="/manual.pdf" />;
}
Follow the React-PDF instructions for the router and release in your project instead of assuming this snippet applies unchanged to every Next.js version. Do not move worker setup into a server module.
Serve the application over HTTP
Mozilla’s PDF.js documentation states that its worker is not enabled for file:// URLs. Opening an HTML file directly from disk can therefore produce worker or loading failures even when the same code works in development. Start your normal development server, such as npm run dev, and test through its http://localhost address. Deployments must likewise serve the JavaScript bundle and worker from a reachable HTTP(S) origin.
Make the viewer usable in a real application
Loading and failure states
Use the loading, error and onLoadSuccess props to provide explicit status. Add an error boundary around the viewer as recommended by React-PDF’s documentation; malformed files, unavailable URLs and runtime rendering errors should not take down the surrounding page.
Page size and responsive layout
Give the viewer a defined container width and let the page scale to it. A common pattern is to measure the container with ResizeObserver and pass a calculated width to Page. Avoid hard-coding a desktop width that causes horizontal scrolling on phones. If you use scale instead, test high-density displays and narrow viewports.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
Text and annotation layers
Import the package’s text-layer and annotation-layer styles when you need selectable text, links or form annotations. Without the expected CSS, text can be offset or invisible over the canvas. Test links, keyboard focus and selection against your application’s global styles.
Navigation, zoom and download
A production viewer commonly adds page number entry, zoom controls, rotation, a download link and an “open in new tab” action. Keep controls as real buttons with accessible names, disable impossible actions, and expose the current page to assistive technology. A native download link can point at the same PDF URL:
<a href="/manual.pdf" download>Download PDF</a>
Browser and version compatibility
Compatibility is version-sensitive. React-PDF’s current documentation covers its 11.x branch, requires React 19+ and Node.js 22.13.0+, and targets current major browsers. Older supported browsers may need polyfills, bundler transpilation or a legacy worker; the examples specifically mention a URL.parse() polyfill for Chrome 125. Verify the matrix for the exact release and browsers you support.
Mozilla’s PDF.js page listed stable version 6.3.289 for modern and older browser builds on September 29, 2026; that listing is a point-in-time record, not a permanent version recommendation.
Rank #4
Alternatives when React-PDF is not the right fit
| Route | Best fit | Important considerations |
|---|---|---|
| React-PDF | A React component API with controls and layout built by your team | Configure the worker, handle client-only loading where required, and add any layer CSS and navigation you need. |
| Mozilla PDF.js layers | Lower-level control or a foundation for a custom viewer | Understand the core, display and viewer layers. Mozilla asks embedders to re-skin or build on the viewer rather than embed an unmodified copy. |
| React PDF Kit | A preassembled React structure and toolbar | Its repository describes a proprietary license; commercial use requires a license. Version 2 defaults to PDF.js 5.4.530 and publishes its own browser matrix. |
| PDF.js Express Plus | A commercial SDK with an official React integration | Copy package assets to a publicly served location, mount WebViewer through a ref and initialize it in an effect. Production requires a commercial license key; its guide says no trial key is required. |
Choose by required controls, customization, browser targets, deployment model and licensing. Published pricing was not established for these options here, so obtain current commercial terms from the vendor before procurement.
Troubleshooting checklist
“Setting up fake worker” or worker-load errors
- Confirm the
GlobalWorkerOptions.workerSrcassignment is in the same module asDocumentandPage. - Check that the installed
pdfjs-distworker path matches the package documentation for your React-PDF version. - Use the development server instead of opening the app with
file://. - Inspect the browser network panel for a 404, blocked MIME type or content-security-policy violation.
The PDF URL returns an error
- Open the URL directly and confirm it returns a PDF rather than an HTML login page.
- For a different origin, configure CORS on the PDF host or proxy the file through your own server.
- Check authentication headers or signed URL expiry; pass request data using the file-object form supported by your installed release.
Next.js crashes during build or hydration
Move the viewer into a client-only module and dynamically import it with ssr: false. Ensure worker configuration is not executed by a server component.
Large files are slow or crash mobile browsers
Render one page at a time, virtualize long lists, constrain image dimensions, and avoid mounting every page simultaneously. Measure memory on the least capable supported device rather than relying only on a desktop test.
Text or links look misaligned
Load the text and annotation layer styles supplied by React-PDF and check that global CSS is not changing the layer’s positioning, line height or pointer events.
Free tools Windows power users keep installed
One-click scans. No signup required.
Best Value
Performance, security and deployment notes
- Prefer HTTPS for document URLs and avoid exposing access tokens in query strings when your server can provide short-lived authenticated URLs.
- Set cache headers appropriate to document sensitivity. Private PDFs should not receive a publicly shareable cache policy.
- Test PDFs with embedded fonts, scanned pages, annotations, encrypted permissions and unusually large images.
- Keep the worker and main PDF.js code on compatible versions; upgrading one without the other can produce opaque runtime failures.
- For accessibility, provide a visible document title, keyboard-operable controls and an alternate download route. Scanned PDFs may need OCR before their text is selectable.
Or skip the browser setup
If your goal is to capture a web page as an image or PDF rather than embed an interactive PDF inside React, ScreenshotNeo provides a single HTTP request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and each response reports its result through X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf tools to Claude, Cursor and other MCP clients.
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 documentation for the full option set, including PDF paper size and margins, device presets, custom CSS and JavaScript, selector capture, waiting rules, headers, cookies, geolocation, signed links, asynchronous jobs and bulk capture.
In Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
In Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I display a PDF with an HTML iframe instead of React-PDF?
Yes, a browser’s built-in PDF viewer can be embedded with an iframe, but it gives your React code little control over page navigation, rendering, annotations and consistent cross-browser behavior. React-PDF is appropriate when those controls belong in your application.
Recommended Free Tools
Why does the same PDF work in one browser but not another?
PDF.js support depends on the browser and the exact package release. Check the release browser matrix, required polyfills and worker choice, then test the target browser rather than inferring support from a single desktop browser.
Does React-PDF upload my document to a third-party service?
React-PDF is a client-side component using PDF.js. Whether a document leaves the browser depends on how your application obtains it; review your own URL, proxy and authentication design for sensitive files.
Should I use React PDF Kit or PDF.js Express Plus for a commercial product?
Evaluate their current license, browser matrix, required controls and deployment process. The cited project documentation states that React PDF Kit commercial use requires a license and PDF.js Express Plus production use requires a commercial key.
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.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →




