A modern, zero-configuration PDF viewer for Angular applications with intelligent auto-fit, text selection, and responsive design.
- 🚀 Zero Configuration - Works out of the box with sensible defaults
- 📱 Responsive Design - Auto-fits to any container size
- 📝 Text Selection - Copy text directly from PDFs
- 🔍 Search Functionality - Find text within documents
- 🖨️ Print & Download - Built-in actions
- 🔄 Zoom & Rotation - Interactive controls
- 📄 Continuous Scrolling - All pages rendered seamlessly
- 🎯 Modern Angular - Standalone components, signals, Angular 19+
- 🛠️ Auto PDF.js Setup - No manual worker configuration needed
npm install ng-pdf-renderer
import { Component } from '@angular/core';
import { PdfViewerComponent } from 'ng-pdf-renderer';
@Component({
selector: 'app-pdf-demo',
standalone: true,
imports: [PdfViewerComponent],
template: `
<ng-pdf-viewer [src]=\"pdfUrl\"></ng-pdf-viewer>
`
})
export class PdfDemoComponent {
pdfUrl = '/assets/document.pdf';
}
That's it! The PDF viewer will automatically:
- Fit the PDF to your container width
- Enable text selection
- Handle high-DPI displays
- Set up PDF.js worker automatically
interface PdfOptions {
// Display Options
height?: string; // Default: '500px'
width?: string; // Default: '100%'
// Auto-Fit Behavior
autoFit?: boolean; // Default: true
initialZoom?: number; // Default: 1.0 (100%)
initialPage?: number; // Default: 1
// Text & Interaction
enableTextSelection?: boolean; // Default: true
renderTextLayer?: boolean; // Default: true
renderAnnotationLayer?: boolean; // Default: true
// Controls Visibility
showControls?: boolean; // Default: false (hidden)
showNavigation?: boolean; // Default: true
showZoomControls?: boolean; // Default: true
showRotationControls?: boolean; // Default: true
showDownloadButton?: boolean; // Default: true
showPrintButton?: boolean; // Default: true
showSearchBar?: boolean; // Default: true
showThumbnails?: boolean; // Default: false
showOutline?: boolean; // Default: false
}
import { Component } from '@angular/core';
import { PdfViewerComponent, PdfOptions } from 'ng-pdf-renderer';
@Component({
selector: 'app-custom-pdf',
standalone: true,
imports: [PdfViewerComponent],
template: `
<ng-pdf-viewer
[src]=\"pdfUrl\"
[options]=\"pdfOptions\"
(pageChange)=\"onPageChange($event)\"
(documentLoaded)=\"onDocumentLoaded($event)\">
</ng-pdf-viewer>
`
})
export class CustomPdfComponent {
pdfUrl = '/assets/document.pdf';
pdfOptions: PdfOptions = {
height: '800px',
showControls: true, // Show control bar
initialZoom: 1.2, // 120% zoom
autoFit: false, // Disable auto-fit
showThumbnails: true // Show thumbnail panel
};
onPageChange(page: number) {
console.log('Current page:', page);
}
onDocumentLoaded(document: any) {
console.log('PDF loaded:', document.numPages, 'pages');
}
}
The autoFit
feature (enabled by default) automatically scales PDFs to fit your container:
- Responsive: Adapts to container width changes
- Scale bounds: Between 10% and 300% for readability
- Container-aware: Calculates optimal zoom based on available space
autoFit: true
(default), manual zoom controls may not work as expected:
// With auto-fit enabled (default):
pdfOptions: PdfOptions = {
showControls: true, // Shows zoom controls
autoFit: true // But auto-fit overrides manual changes!
};
Option 1: Disable Auto-Fit for Manual Control
pdfOptions: PdfOptions = {
autoFit: false, // Disable auto-fit
initialZoom: 1.0, // Set desired zoom
showControls: true // Manual controls work normally
};
Option 2: Use Auto-Fit Only (Recommended)
pdfOptions: PdfOptions = {
autoFit: true, // Let auto-fit handle everything
showControls: false // Hide manual controls to avoid confusion
// PDF scales automatically - no manual intervention needed
};
/* ✅ Good - Let the PDF scale naturally */
.pdf-container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
/* ❌ Avoid - These can cause rendering issues */
.pdf-container {
overflow: hidden; /* Can cut off content */
height: 400px; /* Fixed height without overflow: auto */
max-width: 300px; /* Too restrictive */
}
@Component({
template: `
<ng-pdf-viewer
[src]=\"pdfUrl\"
(pageChange)=\"onPageChange($event)\"
(documentLoaded)=\"onDocumentLoaded($event)\"
(documentLoadError)=\"onError($event)\">
</ng-pdf-viewer>
`
})
export class AdvancedPdfComponent {
onPageChange(pageNumber: number) {
console.log(`User navigated to page ${pageNumber}`);
}
onDocumentLoaded(document: any) {
console.log(`PDF loaded with ${document.numPages} pages`);
}
onError(error: any) {
console.error('PDF loading failed:', error);
}
}
export class PdfSourcesComponent {
// Local file
localPdf = '/assets/document.pdf';
// External URL
externalPdf = 'https://example.com/document.pdf';
// Base64 data
base64Pdf = 'data:application/pdf;base64,JVBERi0xLjQK...';
// Uint8Array (from file upload)
arrayBuffer: Uint8Array;
onFileSelected(event: any) {
const file = event.target.files[0];
if (file.type === 'application/pdf') {
const reader = new FileReader();
reader.onload = (e) => {
this.arrayBuffer = new Uint8Array(e.target?.result as ArrayBuffer);
};
reader.readAsArrayBuffer(file);
}
}
}
PDF not displaying:
// Check console for errors
// Ensure PDF URL is accessible
// Verify CORS headers for external PDFs
Text selection not working:
pdfOptions: PdfOptions = {
enableTextSelection: true, // Ensure this is true
renderTextLayer: true // Required for text selection
};
Manual zoom controls not responding:
pdfOptions: PdfOptions = {
autoFit: false, // Disable auto-fit
showControls: true, // Show controls
initialZoom: 1.0 // Set desired zoom
};
PDF too large/small:
pdfOptions: PdfOptions = {
autoFit: true, // Let auto-fit handle sizing
initialZoom: undefined // Don't override auto-fit
};
Performance issues:
pdfOptions: PdfOptions = {
renderAnnotationLayer: false, // Disable if not needed
showThumbnails: false // Disable heavy features
};
- Chrome: 90+ ✅
- Firefox: 88+ ✅
- Safari: 14+ ✅
- Edge: 90+ ✅
- Angular: 19.1.0 or higher
- Node.js: 18.0.0 or higher
- TypeScript: 5.0 or higher
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT © askinjohn
Made with ❤️ for the Angular community