A production-ready React wrapper around Mozilla's pdf.js that provides a "drop-in" PDF viewer with a fully-featured toolbar, find bar, and automatic state persistence.
- Batteries Included: Full toolbar with page navigation, zoom, rotation, print, download, and fullscreen out of the box.
- State Persistence: Automatically saves and restores scroll position (precise ratio), zoom level, and rotation for each document.
- Find Bar:
Ctrl+F/Cmd+Fsupport with highlighting, match case, and whole word options. - Feature Flags: Easily opt-out of specific features (e.g., disable rotation or the toolbar) via props.
- Simple API: Just pass a
File,Blob, or URL string. - TypeScript: First-class type definitions included.
# npm
npm install custom-react-pdf-viewer
# pnpm
pnpm add custom-react-pdf-viewer
# yarn
yarn add custom-react-pdf-viewerRequirements:
reactandreact-dom(>=18 <20) are peer dependencies — provide them from your app (you almost certainly already have them).pdf.jsis pulled in automatically as a pinned dependency, so there's nothing extra to install; it's pinned to an exact version (currently6.0.227) rather than a range because the viewer integrates deeply withpdf.jsinternals and ships its stylesheet built against that exact release, so it's bumped deliberately with each version.
If you just want to render a PDF without worrying about state or persistence, simply import the component and pass it a file.
Note:* The viewer is designed to fill 100% of the width and height of its parent container. Ensure the parent element has a defined height (e.g., 100vh, 500px, or flex: 1).
import { CustomPdfViewer } from "custom-react-pdf-viewer";
import "custom-react-pdf-viewer/style.css"; // Don't forget the styles!
function SimpleViewer({ fileBlob }) {
return (
<div style={{ height: "100vh" }}>
<CustomPdfViewer
file={fileBlob}
fileName="my-document.pdf"
/>
</div>
);
}To automatically remember zoom levels and scroll positions when users switch between documents, you need two things:
- Wrap your app with the
<PdfStoreProvider>. - Give your viewer a unique
viewerId.
// src/main.tsx
import { PdfStoreProvider } from "custom-react-pdf-viewer";
<PdfStoreProvider>
<App />
</PdfStoreProvider>// src/App.tsx
import { CustomPdfViewer } from "custom-react-pdf-viewer";
function App() {
// ... file loading logic ...
return (
<CustomPdfViewer
file={file}
fileName="sample.pdf"
// 1. Required: Unique ID for this UI slot (e.g. "main-viewer", "sidebar")
viewerId="main-pdf-viewer"
// 2. Recommended: Unique ID for the document content
sessionKey="doc-123"
/>
);
}Result: If a user zooms to 150%, switches to another document, and returns to "doc-123", the viewer will automatically restore the zoom level and exact scroll position.
By default, the PdfStoreProvider uses in-memory storage, meaning state is lost on refresh.
To persist state across browser restarts, pass LocalStorageStore to the provider.
import { PdfStoreProvider, LocalStorageStore } from "custom-react-pdf-viewer";
<PdfStoreProvider store={new LocalStorageStore()}>
<App />
</PdfStoreProvider>The component usage (viewerId, sessionKey) remains exactly the same as in Level 2.
| Prop | Type | Description |
|---|---|---|
file |
Blob | File | string | null |
Required. The source of the PDF. |
fileName |
string |
Optional. The name shown in the toolbar and used for downloads. |
documentTitle |
string |
Optional. Overrides the displayed title. Defaults to fileName. |
viewerId |
string |
Required for persistence. Unique identifier for this viewer slot. |
sessionKey |
string |
Optional. Identifies the document; if it changes, the viewer treats it as a new document. |
persistenceStore |
PdfPersistenceStore |
Optional. Store override for this instance; falls back to the PdfStoreProvider context. |
disabledFeatures |
string[] |
Optional. Features to hide: "toolbar", "find", "rotation", "zoom", "pagination", "print", "download". |
highlightInfo |
{ [page: number]: string } | null |
Optional. Text to highlight, keyed by page number. |
jumpToPage |
number | null |
Optional. Programmatically scroll to a page. |
iconSet |
IconSet |
Optional. Icon set for the toolbar and menu. Defaults to Lucide. |
toolbarSize |
'sm' | 'md' | 'lg' |
Optional. Toolbar size preset. Defaults to 'md'. |
onOpen |
() => void |
Optional. Wires the menu's "Open" item; omit to hide it. |
onClose |
() => void |
Optional. Wires the menu's "Close" item; omit to hide it. |
allowDownload |
boolean |
Optional. Allow downloading the document. Default true. |
allowPrint |
boolean |
Optional. Allow printing the document. Default true. |
allowFullscreen |
boolean |
Optional. Allow toggling fullscreen. Default true. |
<CustomPdfViewer
file={file}
disabledFeatures={['rotation', 'find']}
/>:root {
/* Toolbar & Backgrounds */
--custom-pdf-toolbar-bg: #f9f9fa;
--custom-pdf-toolbar-border-color: #b8b8b8;
--custom-pdf-viewer-bg: #f1f5f9;
--custom-pdf-main-color: #181819;
/* Accent Colors */
--custom-pdf-accent-color: #0a84ff;
--custom-pdf-button-hover-color: #ddd;
}Apache-2.0 © Roland Arnold
