React PDF Viewer
A plugin-based React component, built on pdf.js, for viewing and interacting with PDF documents.
Repository Health
Technical Analysis
React PDF Viewer’s core package renders PDF documents inside React applications by wrapping Mozilla’s pdf.js. It exposes a single Viewer component that consumers extend through a plugin system: separate npm packages (toolbar, zoom, search, thumbnail, print, bookmark, and more) each register lifecycle hooks and share state through a lightweight pub/sub store, so an app can compose exactly the reader features it needs rather than pulling in a monolithic viewer.
The library is written entirely in TypeScript with React hooks, supports SSR, virtualized page rendering, password-protected documents, theming and dark mode, RTL layouts, and localization. It’s free to use in the source-available repository, but the project’s license requires purchasing a commercial license for use, distinguishing it from typical MIT-licensed React libraries.
What You Get
- A core
Viewercomponent that loads and renders PDF pages from a URL or byte array, with virtualized rendering so only visible pages mount - Two dozen official plugin packages (toolbar, default-layout, zoom, search, thumbnail, print, bookmark, attachment, rotate, highlight, and others) that can be mixed and matched per app
- A typed
Plugininterface (install/uninstall, renderViewer, renderPageLayer, onDocumentLoad, onViewerStateChange) for writing custom plugins against the same lifecycle the official ones use - Built-in support for password-protected PDFs, print, full-screen mode, dark/light theming, right-to-left layouts, and string localization
- SSR-safe rendering, verified against both Webpack and Next.js demo apps included in the monorepo
Common Use Cases
- Embedding an in-app document viewer for reports, invoices, or contracts without leaving the page
- Building a custom PDF toolbar (zoom, page navigation, search, download) by composing only the plugins an app needs
- Viewing password-protected or access-controlled PDFs with custom authentication headers
- Adding PDF preview to admin dashboards, document-management tools, or content platforms
- Rendering PDFs inside SSR frameworks like Next.js where the viewer must hydrate cleanly on the client
Under The Hood
Architecture
The core Viewer component (packages/core/src/Viewer.tsx) composes a DocumentLoader (which owns the pdf.js document-loading state machine — loading, password-prompt, failure, completed) with an Inner layout that virtualizes page rendering via PageSizeCalculator and a render-range callback. Extensibility comes from a Plugin interface (packages/core/src/types/Plugin.ts) with optional install/uninstall/renderViewer/renderPageLayer/onDocumentLoad/onViewerStateChange hooks; each of the ~20 sibling packages (toolbar, zoom, search, thumbnail, print, bookmark, etc.) is an independently published plugin exposing a factory function (e.g. defaultLayoutPlugin()) that returns a Plugin object, optionally declaring dependencies on other plugins. Cross-plugin communication happens through a minimal pub/sub store (packages/core/src/store/createStore.ts) that plugin instances subscribe to and update, avoiding a shared global state library. This gives a genuinely modular, event-driven composition where an app only pays for the plugins it imports.
Tech Stack
Entirely TypeScript with React (peer dependency >=16.8.0) built on React hooks; pdf.js is injected by the consumer through a PdfJsApiContext rather than bundled directly, keeping the core package decoupled from a specific pdf.js version. The monorepo (20+ packages under packages/*) is orchestrated with Turborepo and npm workspaces, built per-package with Rollup plus esbuild, and styled with CSS Modules processed through PostCSS. Demo apps under demo/webpack and demo/nextjs exercise both a plain Webpack setup and Next.js SSR to validate real-world integration.
Code Quality
The repo has extensive test coverage — 92+ Jest test files across packages, including Puppeteer-driven end-to-end tests (jest-e2e.config.ts) that render real PDFs from the samples/ directory and assert on DOM/visual behavior (rotation, zoom, password prompts, strict-mode compatibility, RTL). Per-package tsconfig.json files enable strict: true, and ESLint is configured with @typescript-eslint plus plugin:react/recommended. Naming and file organization are consistent across all plugin packages (each mirrors the same src/ layout), and error states (load failure, missing PDF, wrong password) are modeled as explicit typed states rather than caught-and-swallowed exceptions.
What Makes It Unique Most React PDF-rendering libraries expose one large configurable component; this project instead ships each toolbar feature (zoom, search, thumbnails, printing, bookmarks, attachments, highlighting) as its own independently installable plugin package sharing one small store contract, letting consumers assemble a custom reader UI with only the code paths they use. The trade-off is the project’s licensing: unlike most npm libraries, using it beyond evaluation requires purchasing a commercial license from the maintainer.