
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
@vvelediaz/react-pdf-viewer
Advanced tools
A modern, lightweight React PDF viewer component featuring zoom controls, page navigation, and responsive design
A modern, feature-rich React PDF viewer component with a classic Mac OS X Aqua interface. Perfect for desktop and web applications requiring elegant PDF display capabilities with zero configuration hassles.
# npm
npm install @vvelediaz/react-pdf-viewer
# Yarn
yarn add @vvelediaz/react-pdf-viewer
# pnpm
pnpm add @vvelediaz/react-pdf-viewer
# Bun
bun add @vvelediaz/react-pdf-viewer
After installation, you need to set up the PDF.js worker file. Choose one of these methods:
# Copy the PDF worker to your public directory
cp node_modules/@vvelediaz/react-pdf-viewer/public/pdf.worker.min.js public/
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer'
// Call once in your app's entry point (main.tsx, index.tsx, or App.tsx)
setupPDFJS() // Uses CDN fallback automatically
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer'
// Use a custom worker path
setupPDFJS('https://your-cdn.com/pdf.worker.min.js')
import React from 'react'
import { PDFViewer } from '@vvelediaz/react-pdf-viewer'
// Required CSS imports
import 'react-pdf/dist/Page/AnnotationLayer.css'
import 'react-pdf/dist/Page/TextLayer.css'
// Copy PDFViewer.css from the GitHub repo to your project
function MyApp() {
const handleLoadSuccess = (pdf) => {
console.log('PDF loaded with', pdf.numPages, 'pages')
}
const handlePageChange = (pageNumber) => {
console.log('Current page:', pageNumber)
}
return (
<PDFViewer
file="/path/to/document.pdf"
width="100%"
height="600px"
onLoadSuccess={handleLoadSuccess}
onPageChange={handlePageChange}
scrollMode="continuous"
initialZoom={1.2}
/>
)
}
The component automatically handles PDF.js worker setup with zero configuration required:
If you need custom worker configuration:
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer'
// Call once in your app's entry point
setupPDFJS()
Add to your vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
optimizeDeps: {
include: ['react-pdf', 'pdfjs-dist'],
},
})
Add to your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['react-pdf'],
webpack: (config) => {
config.resolve.alias.canvas = false
return config
},
}
module.exports = nextConfig
module.exports = {
resolve: {
alias: {
canvas: false,
},
},
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
},
],
},
}
Solution: Copy the worker file to your public directory:
cp node_modules/@vvelediaz/react-pdf-viewer/public/pdf.worker.min.js public/
Solution: Use the setupPDFJS() function with CDN fallback:
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer'
setupPDFJS() // Automatically uses CDN if local file not found
Solution: Ensure your server serves .js files with correct MIME type, or use CDN:
setupPDFJS('https://unpkg.com/pdfjs-dist@4.8.69/build/pdf.worker.min.js')
Fixed: Component uses local worker files with CDN fallback automatically.
Fixed: Automatic version matching between react-pdf and PDF.js worker.
Fixed: Zero-config setup works out of the box with automatic fallbacks.
Fixed: Package now ships as compiled JavaScript instead of raw TypeScript, eliminating Vite externalization issues.
Previous Error: Module "npm:react@^18.2.0" has been externalized for browser compatibility
Solution: The package is now properly built as a library with React as an external dependency.
Solutions:
Solutions:
scrollMode="page" for very large documentsinitialZoom valuesSolutions:
@types/react and @types/react-dom are installedimport type { PDFViewerProps } from '@vvelediaz/react-pdf-viewer/types'Works in all modern browsers that support:
Tested Browsers:
| Prop | Type | Default | Description |
|---|---|---|---|
file | string | File | ArrayBuffer | Required | PDF source - URL, File object, or ArrayBuffer |
width | string | number | '100%' | Component width |
height | string | number | '600px' | Component height |
onLoadSuccess | (pdf: PDFDocumentProxy) => void | - | Called when PDF loads successfully |
onLoadError | (error: Error) => void | - | Called when PDF fails to load |
onPageChange | (pageNumber: number) => void | - | Called when current page changes |
onZoomChange | (scale: number) => void | - | Called when zoom level changes |
className | string | '' | Additional CSS classes |
initialPage | number | 1 | Starting page number |
initialZoom | number | 1.0 | Starting zoom level (0.5 - 3.0) |
scrollMode | 'page' | 'continuous' | 'page' | View mode for PDF display |
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer'
// Configure PDF.js worker (call once in your app)
setupPDFJS()
import type {
PDFViewerProps,
PDFDocumentProxy,
PDFPageProxy,
PDFLoadSuccess,
PDFError
} from '@vvelediaz/react-pdf-viewer/types'
import React, { useState } from 'react'
import { PDFViewer } from '@vvelediaz/react-pdf-viewer'
function PDFUploader() {
const [pdfFile, setPdfFile] = useState<File | null>(null)
const [error, setError] = useState<string | null>(null)
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (!file) return
// Validate file type
if (!file.type.includes('pdf') && !file.name.toLowerCase().endsWith('.pdf')) {
setError('Please select a valid PDF file')
return
}
// Validate file size (10MB limit)
if (file.size > 10 * 1024 * 1024) {
setError('File size must be less than 10MB')
return
}
setError(null)
setPdfFile(file)
}
return (
<div>
<input
type="file"
accept=".pdf,application/pdf"
onChange={handleFileChange}
/>
{error && <div className="error">{error}</div>}
{pdfFile && (
<PDFViewer
file={pdfFile}
height="500px"
scrollMode="continuous"
onLoadError={(err) => setError(err.message)}
/>
)}
</div>
)
}
import React, { useState } from 'react'
import { PDFViewer } from '@vvelediaz/react-pdf-viewer'
function PDFWithStates() {
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [pageCount, setPageCount] = useState(0)
const handleLoadSuccess = (pdf) => {
setPageCount(pdf.numPages)
setLoading(false)
setError(null)
}
const handleLoadError = (err: Error) => {
setError(`Failed to load PDF: ${err.message}`)
setLoading(false)
}
return (
<div>
{loading && <div className="loading">Loading PDF...</div>}
{error && (
<div className="error">
<h3>Error</h3>
<p>{error}</p>
<button onClick={() => {
setError(null)
setLoading(true)
}}>
Retry
</button>
</div>
)}
{!loading && !error && (
<div className="pdf-info">
Document loaded successfully ({pageCount} pages)
</div>
)}
<PDFViewer
file="/path/to/document.pdf"
onLoadSuccess={handleLoadSuccess}
onLoadError={handleLoadError}
/>
</div>
)
}
The component features an authentic classic Mac OS X Aqua design:
// Essential react-pdf styles
import 'react-pdf/dist/Page/AnnotationLayer.css'
import 'react-pdf/dist/Page/TextLayer.css'
// Component styles (copy from GitHub repo)
import './PDFViewer.css'
/* Override default styles */
.pdf-viewer {
--aqua-blue: #007AFF;
--metal-bg: linear-gradient(to bottom, #E8E8E8, #D0D0D0);
--button-gradient: linear-gradient(to bottom, #F8F8F8, #E0E0E0);
}
/* Custom scrollbar colors */
.pdf-content::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #FF6B6B, #FF5252) !important;
}
import React, { useState } from 'react'
import { PDFViewer } from '@vvelediaz/react-pdf-viewer'
function MultiPDFViewer() {
const documents = [
{ id: 1, name: 'Document 1', url: '/doc1.pdf' },
{ id: 2, name: 'Document 2', url: '/doc2.pdf' },
{ id: 3, name: 'Document 3', url: '/doc3.pdf' },
]
const [activeDoc, setActiveDoc] = useState(documents[0])
return (
<div>
<div className="tabs">
{documents.map(doc => (
<button
key={doc.id}
className={activeDoc.id === doc.id ? 'active' : ''}
onClick={() => setActiveDoc(doc)}
>
{doc.name}
</button>
))}
</div>
<PDFViewer
key={activeDoc.id} // Force re-render when switching docs
file={activeDoc.url}
height="600px"
scrollMode="page"
/>
</div>
)
}
scrollMode="page" for large documents (>50 pages)initialZoom based on your use caseReact.memo for wrapper components to avoid unnecessary re-renders<link rel="preload"> in your HTMLWe welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/yourusername/react-pdf-viewer.git
# Install dependencies
bun install
# Start development server (auto-copies worker files)
bun run dev
# Run type checking
bun run type-check
# Build for production
bun run build
MIT License - see the LICENSE file for details.
FAQs
A modern, lightweight React PDF viewer component featuring zoom controls, page navigation, and responsive design
We found that @vvelediaz/react-pdf-viewer demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.