@vvelediaz/react-pdf-viewer@0.3.0
@vvelediaz/react-pdf-viewer
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.
✨ Features
- 📄 Universal PDF Support - Display PDFs from URLs, File objects, or ArrayBuffers
- 🔍 Advanced Zoom Controls - Zoom from 50% to 300% with smooth scaling
- 🖥️ Classic Mac OS X Aqua Design - Authentic Aqua interface with brushed metal toolbars
- ⬅️➡️ Page Navigation - Intuitive page controls with jump-to-page functionality
- 📜 Multiple View Modes - Single page or continuous scroll viewing
- ⚡ High Performance - Efficient rendering with react-pdf
- 🎨 Beautiful UI - Classic Mac interface with proper gradients, shadows, and typography
- 🔧 TypeScript Support - Fully typed for better development experience
- 🌐 Cross Platform - Works on all modern browsers and desktop applications
- ⚛️ React 19 Ready - Fully compatible with React 18 and 19
- 🎯 Minimal Dependencies - Only essential dependencies for maximum compatibility
- 🚫 Zero CORS Issues - Local worker files eliminate cross-origin problems
- 🔄 Auto-Configuration - Automatic PDF.js worker setup with version matching
📦 Installation
Using JSR (Recommended)
# Deno deno add @vvelediaz/react-pdf-viewer # npm npx jsr add @vvelediaz/react-pdf-viewer # Yarn yarn dlx jsr add @vvelediaz/react-pdf-viewer # pnpm pnpm dlx jsr add @vvelediaz/react-pdf-viewer # Bun bunx jsr add @vvelediaz/react-pdf-viewer
Using npm
npm install @vvelediaz/react-pdf-viewer
🚀 Quick Start
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} /> ) }
🛠️ Setup & Configuration
Automatic PDF.js Configuration
The component automatically handles PDF.js worker setup with zero configuration required:
- ✅ Auto-detects correct worker version
- ✅ Eliminates CORS issues with local worker files
- ✅ Matches API versions automatically
- ✅ No manual setup needed
Manual Configuration (Optional)
If you need custom worker configuration:
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer' // Call once in your app's entry point setupPDFJS()
Bundler Configuration
Vite (Recommended)
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'], }, })
Next.js
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
Webpack
module.exports = { resolve: { alias: { canvas: false, }, }, module: { rules: [ { test: /\.mjs$/, include: /node_modules/, type: 'javascript/auto', }, ], }, }
🔧 Troubleshooting
Common Issues & Solutions
✅ "No CORS Errors"
Fixed: Component uses local worker files automatically.
✅ "No Version Mismatches"
Fixed: Automatic version matching between react-pdf and PDF.js worker.
✅ "No Configuration Required"
Fixed: Zero-config setup works out of the box.
PDF Not Loading
Solutions:
- Check file path/URL is correct
- Verify file is a valid PDF
- Check browser console for specific errors
- Ensure required CSS files are imported
Memory Issues with Large PDFs
Solutions:
- Use
scrollMode="page"
for very large documents - Implement lazy loading for multiple PDFs
- Consider using lower
initialZoom
values
TypeScript Errors
Solutions:
- Ensure
@types/react
and@types/react-dom
are installed - Import types:
import type { PDFViewerProps } from '@vvelediaz/react-pdf-viewer/types'
Browser Compatibility
Works in all modern browsers that support:
- ✅ ES2018+ features
- ✅ Web Workers
- ✅ ArrayBuffer and Blob APIs
- ✅ CSS Grid and Flexbox
Tested Browsers:
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
📚 API Reference
PDFViewer Props
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 |
Utility Functions
import { setupPDFJS } from '@vvelediaz/react-pdf-viewer' // Configure PDF.js worker (call once in your app) setupPDFJS()
Types
import type { PDFViewerProps, PDFDocumentProxy, PDFPageProxy, PDFLoadSuccess, PDFError } from '@vvelediaz/react-pdf-viewer/types'
🛠️ Advanced Usage
File Upload with Validation
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> ) }
Custom Error Handling & Loading States
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> ) }
🎨 Styling
Classic Mac OS X Aqua Interface
The component features an authentic classic Mac OS X Aqua design:
- 🖥️ Brushed Metal Toolbars - Authentic metal texture with subtle striped patterns
- 🔵 Classic Aqua Buttons - Proper gradients, shadows, and hover effects
- 📜 Blue Aqua Scrollbars - Traditional Mac scrollbar styling
- 📝 Lucida Grande Typography - System font matching the classic Mac experience
Required CSS Imports
// 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'
Custom Styling
/* 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; }
Multiple PDF Viewer with Tabs
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> ) }
📱 Platform Support
- ✅ Web Browsers - Chrome, Firefox, Safari, Edge (latest versions)
- ✅ Desktop Apps - Electron, Tauri, and other desktop frameworks
- ✅ Mobile Web - iOS Safari, Android Chrome (responsive design)
- ✅ PWA - Progressive Web Applications
- ✅ Server-Side - Next.js, Remix (with proper configuration)
🔧 Requirements
- React 18+ or 19+
- Modern Browser with PDF.js support
- No additional UI frameworks required
- TypeScript 5+ (optional but recommended)
📈 Performance Tips
- Use
scrollMode="page"
for large documents (>50 pages) - Implement lazy loading when displaying multiple PDFs
- Set appropriate
initialZoom
based on your use case - Use
React.memo
for wrapper components to avoid unnecessary re-renders - Preload critical PDFs using
<link rel="preload">
in your HTML
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# 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
📄 License
MIT License - see the LICENSE file for details.
🔗 Links
- JSR Package - Official package registry
- GitHub Repository - Source code and issues
- React PDF - Underlying PDF rendering library
- PDF.js - Mozilla's PDF rendering engine
🎯 Roadmap
- Dark mode support for Aqua interface
- Annotation tools (highlight, comments)
- Search functionality within PDFs
- Thumbnail navigation sidebar
- Print support with custom styling
- Accessibility improvements (ARIA labels, keyboard navigation)
- Mobile gestures (pinch to zoom, swipe navigation)
Add Package
deno add jsr:@vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";
Import directly with a jsr specifier
import * as react_pdf_viewer from "jsr:@vvelediaz/react-pdf-viewer";
Add Package
pnpm i jsr:@vvelediaz/react-pdf-viewer
pnpm dlx jsr add @vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";
Add Package
yarn add jsr:@vvelediaz/react-pdf-viewer
yarn dlx jsr add @vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";
Add Package
vlt install jsr:@vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";
Add Package
npx jsr add @vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";
Add Package
bunx jsr add @vvelediaz/react-pdf-viewer
Import symbol
import * as react_pdf_viewer from "@vvelediaz/react-pdf-viewer";