Frequently Asked Questions (FAQ)
Common questions and answers about ng2-pdfjs-viewer. This FAQ is compiled from recurring GitHub issues and Stack Overflow questions.
🔐 Authentication & CORS
How do I handle CORS issues with AWS S3 or external domains?
Problem: Getting CORS errors when loading PDFs from S3, CDN, or external domains.
Solutions:
- Server-side: Configure CORS headers on your S3 bucket/server:
<!-- S3 CORS Configuration -->
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>https://your-domain.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
- Client-side: Load PDF as Blob via your backend proxy:
this.http.get(s3Url, { responseType: 'blob' }).subscribe(blob => {
this.pdfViewer.pdfSrc = blob;
this.pdfViewer.refresh();
});
References: #9, Stack Overflow
How do I add authentication headers (JWT, Bearer tokens)?
Problem: PDF endpoint requires Authorization header, but can't pass headers directly to pdfSrc.
Solution: Fetch PDF through your HTTP client, then pass Blob:
export class MyComponent {
downloadPdf() {
const headers = new HttpHeaders({
'Authorization': `Bearer ${this.token}`
});
this.http.get('https://api.example.com/pdf', {
headers,
responseType: 'blob'
}).subscribe(blob => {
this.pdfViewer.pdfSrc = blob;
this.pdfViewer.refresh();
});
}
}
How do I enable fullscreen when viewer and PDF are from different domains?
Problem: Fullscreen doesn't work when using CDN for viewer files and different domain for PDF.
Workaround: Currently requires adding allowfullscreen attribute to iframe (feature request pending).
References: #141
🎨 UI Customization
How do I hide the toolbar completely?
Problem: Want to show only PDF content without any controls.
Solution: Use CSS to hide the toolbar:
// Component
customCSS = `
#toolbarContainer {
display: none !important;
}
#viewerContainer {
top: 0 !important;
}
`;
<ng2-pdfjs-viewer
[pdfSrc]="pdfSrc"
[customCSS]="customCSS">
</ng2-pdfjs-viewer>
Alternative: Hide individual sections:
<ng2-pdfjs-viewer
[openFile]="false"
[download]="false"
[print]="false"
[viewBookmark]="false"
[fullScreen]="false">
</ng2-pdfjs-viewer>
How do I remove iframe border or make PDF full width?
Solution 1 - Remove border:
/* Global styles.css */
ng2-pdfjs-viewer iframe {
border: none !important;
}
Solution 2 - Full width:
customCSS = `
#mainContainer {
min-width: unset !important;
}
.page {
max-width: 100% !important;
}
`;
How do I prevent sidebar from opening/flickering randomly?
Problem: Sidebar sometimes opens automatically or flickers on load.
Solution: Control sidebar in onDocumentLoad:
loadComplete() {
this.pdfViewer.PDFViewerApplication.pdfSidebar.close();
}
<ng2-pdfjs-viewer
(onDocumentLoad)="loadComplete()"
viewerId="myViewer">
</ng2-pdfjs-viewer>
References: #166
How do I enable hand tool by default?
Solution:
loadComplete() {
const app = this.pdfViewer.PDFViewerApplication;
app.pdfCursorTools.switchTool(1); // 0 = text selection, 1 = hand tool
}
References: #163
🔄 Lifecycle & Initialization
Why doesn't onDocumentLoad fire when viewer is hidden?
Problem: Using *ngIf or [hidden] prevents events from firing.
Solutions:
- Use visibility instead of display:none:
<div [style.visibility]="isLoading ? 'hidden' : 'visible'">
<ng2-pdfjs-viewer (onDocumentLoad)="loadComplete()"></ng2-pdfjs-viewer>
</div>
- Use opacity:
<div [style.opacity]="isLoading ? 0 : 1">
<ng2-pdfjs-viewer (onDocumentLoad)="loadComplete()"></ng2-pdfjs-viewer>
</div>
- Keep viewer mounted, hide with CSS:
.hidden-viewer {
position: absolute;
left: -9999px;
visibility: hidden;
}
Why: iframe needs to be in DOM and visible for postMessage to work.
References: #167, Stack Overflow
How do I display an empty viewer when no file is provided?
Solution: Always provide a valid pdfSrc or conditionally render:
export class MyComponent {
pdfSrc: string | Blob | null = null;
showViewer = false;
loadPdf(url: string) {
this.pdfSrc = url;
this.showViewer = true;
}
}
<ng2-pdfjs-viewer
*ngIf="showViewer && pdfSrc"
[pdfSrc]="pdfSrc">
</ng2-pdfjs-viewer>
References: Stack Overflow
How do I clear/reset the viewer or load a new PDF?
Solution: Update pdfSrc and call refresh():
loadNewPdf(newUrl: string) {
this.pdfViewer.pdfSrc = newUrl;
this.pdfViewer.refresh();
}
clearViewer() {
this.pdfViewer.pdfSrc = null;
// Or hide the component
this.showViewer = false;
}
References: #90
📱 Mobile & Print
Why don't Print and Download work on mobile devices?
Problem: Print/Download buttons don't work on iPhone, iPad, or Android.
Cause: Browser limitations on mobile devices restrict iframe print/download functionality.
Workarounds:
- Download: Use native download via anchor tag:
downloadPdf() {
const link = document.createElement('a');
link.href = this.pdfUrl;
link.download = 'document.pdf';
link.click();
}
- Print: Open in new window:
<ng2-pdfjs-viewer [externalWindow]="true"></ng2-pdfjs-viewer>
References: #177
How do I improve print quality (resolution)?
Problem: Printed PDFs have low quality (150 DPI).
Solution: This is controlled by PDF.js rendering settings. For production, consider upgrading to PDF.js v3+ which has better print resolution defaults.
Temporary workaround: Modify pdf.js constant PRINT_RESOLUTION from 150 to 600 (not recommended for library users).
References: #179
🎯 Advanced Features
How do I trigger download from an external button?
Problem: Want custom download button without reload.
Solution: Access PDFViewerApplication directly:
@ViewChild('pdfViewer') pdfViewer: PdfJsViewerComponent;
downloadPdf() {
this.pdfViewer.PDFViewerApplication.download();
}
<button (click)="downloadPdf()">Download</button>
<ng2-pdfjs-viewer
#pdfViewer
[download]="false"
viewerId="myViewer">
</ng2-pdfjs-viewer>
References: #103
How do I capture click or mouse events on the PDF?
Solution: Access canvas elements after document loads:
loadComplete() {
const pages = this.pdfViewer.PDFViewerApplication.pdfViewer._pages;
pages.forEach((page, index) => {
page.canvas.addEventListener('click', (event) => {
console.log(`Clicked on page ${index + 1}`, {
x: event.offsetX,
y: event.offsetY
});
});
});
}
Note: Text layer sits above canvas by default. Disable it for better event handling:
customCSS = `.textLayer { pointer-events: none; }`;
How do I search content and navigate to results?
Solution: Use PDFViewerApplication's findController:
searchPdf(query: string) {
const app = this.pdfViewer.PDFViewerApplication;
app.findController.executeCommand('find', {
query: query,
highlightAll: true,
caseSensitive: false
});
}
findNext() {
this.pdfViewer.PDFViewerApplication.findController.executeCommand('findagain', {
query: this.lastQuery,
findPrevious: false
});
}
References: #113
How do I remember the last page viewed (bookmarks)?
Solution: Listen to page changes and store in localStorage:
loadComplete() {
const app = this.pdfViewer.PDFViewerApplication;
// Restore last page
const lastPage = localStorage.getItem('pdf_last_page');
if (lastPage) {
app.page = parseInt(lastPage);
}
// Track page changes
app.eventBus.on('pagechanging', (e) => {
localStorage.setItem('pdf_last_page', e.pageNumber);
});
}
References: #138
How do I open multiple PDFs side-by-side in new windows?
Problem: externalWindow reuses the same tab.
Solution: Use unique viewerId for each instance:
<!-- First PDF -->
<ng2-pdfjs-viewer
[pdfSrc]="pdf1"
[externalWindow]="true"
viewerId="viewer1">
</ng2-pdfjs-viewer>
<!-- Second PDF -->
<ng2-pdfjs-viewer
[pdfSrc]="pdf2"
[externalWindow]="true"
viewerId="viewer2">
</ng2-pdfjs-viewer>
References: #174
How do I load password-protected PDFs?
Problem: PDFs with password protection don't load.
Current Status: Not directly supported via component attribute.
Workaround: PDF.js will show native password prompt. To pre-populate password, you'd need to modify PDF.js source or handle via backend (decrypt/proxy).
References: #165
How do I add a watermark to the PDF?
Solution: Add watermark overlay using CSS:
customCSS = `
.page::after {
content: "CONFIDENTIAL";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
font-size: 72px;
color: rgba(255, 0, 0, 0.2);
pointer-events: none;
z-index: 9999;
}
`;
Note: This is visual only - doesn't modify the actual PDF file.
References: #104
How do I load PDFs offline or from IndexedDB (PWA)?
Problem: Loading Blob from IndexedDB fails offline on iOS Safari.
Solution: Ensure you load as Uint8Array instead of Blob:
// IndexedDB retrieval
const pdfData = await db.getPdf(id); // Returns ArrayBuffer
const uint8Array = new Uint8Array(pdfData);
this.pdfViewer.pdfSrc = uint8Array;
this.pdfViewer.refresh();
References: #129
🐛 Common Errors & Troubleshooting
What is viewerId and when do I need it?
Answer: viewerId is required only when using events like onDocumentLoad, onPageChange, etc.
<!-- ❌ Events won't work -->
<ng2-pdfjs-viewer
(onDocumentLoad)="loadComplete()">
</ng2-pdfjs-viewer>
<!-- ✅ Correct -->
<ng2-pdfjs-viewer
viewerId="myViewer"
(onDocumentLoad)="loadComplete()">
</ng2-pdfjs-viewer>
Why: Events use postMessage between iframe and parent, requiring unique ID for routing.
References: #134
Error: "offsetParent is not set -- cannot scroll"
Problem: Console shows scroll error, PDF may not display properly.
Cause: Viewer rendered in hidden container or Bootstrap/Material components with display: none.
Solution:
/* Don't use display: none, use visibility */
.pdf-container {
visibility: visible; /* or hidden */
}
/* Ensure parent has layout */
.pdf-wrapper {
position: relative;
width: 100%;
height: 600px;
}
References: #171
Why does viewer scroll vertically on load randomly?
Problem: PDF sometimes loads scrolled down instead of at top.
Cause: Browser scroll position restored or PDF has internal open action.
Solution: Force scroll to top after load:
loadComplete() {
const container = this.pdfViewer.PDFViewerApplication.pdfViewer.container;
container.scrollTop = 0;
}
References: #95
Why does diagnosticLogs="false" still show logs?
Problem: Console still shows "PDF.js: 2.2.171" messages.
Cause: Some logs are from PDF.js core, not controlled by the component.
Workaround: These are informational and safe to ignore in production builds.
References: #97
📄 Document Loading
Why does my Blob/Uint8Array not load or show wrong PDF?
Problem: Loading PDF from Blob shows TypeError or loads wrong document.
Solution (Fixed in latest version): Ensure you're loading in ngAfterViewInit:
@ViewChild('pdfViewer') pdfViewer: PdfJsViewerComponent;
ngAfterViewInit() {
this.http.get(url, { responseType: 'blob' }).subscribe(blob => {
this.pdfViewer.pdfSrc = blob;
this.pdfViewer.refresh();
});
}
References: #283
How do I load PDFs from Google Drive or redirect URLs?
Problem: Google Drive URLs return HTML redirect page instead of PDF.
Solution: Use direct download link format:
// ❌ Wrong - Sharing link
const url = 'https://drive.google.com/file/d/FILE_ID/view';
// ✅ Correct - Direct download
const url = 'https://drive.google.com/uc?export=download&id=FILE_ID';
Better: Download via backend to avoid CORS:
this.http.get('/api/proxy-drive-pdf?id=' + fileId, {
responseType: 'blob'
}).subscribe(blob => {
this.pdfViewer.pdfSrc = blob;
this.pdfViewer.refresh();
});
References: #175
🖨️ Print & Download
How do I customize the download behavior or filename?
Solution: Intercept download and handle manually:
@ViewChild('pdfViewer') pdfViewer: PdfJsViewerComponent;
customDownload() {
const blob = new Blob([this.pdfData], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'my-custom-filename.pdf';
link.click();
URL.revokeObjectURL(link.href);
}
<ng2-pdfjs-viewer
[download]="false"
[pdfSrc]="pdfSrc">
</ng2-pdfjs-viewer>
<button (click)="customDownload()">Download PDF</button>
References: #103, Stack Overflow
🎨 Customization Examples
How do I customize icons or toolbar buttons?
Solution: Use customCSS to override button icons:
customCSS = `
#print::before {
content: url('data:image/svg+xml;base64,YOUR_ICON_BASE64');
}
/* Or use Font Awesome */
#download::before {
content: "\f019"; /* FontAwesome download icon */
font-family: "Font Awesome 5 Free";
}
`;
References: Stack Overflow
How do I use custom Worker URL?
Problem: Need to use custom or CDN-hosted PDF worker.
Solution: Set before viewer initializes:
ngOnInit() {
// Must set before viewer loads
(window as any).pdfWorkerSrc = '/path/to/custom-pdf.worker.js';
}
References: #101
🔧 Configuration & Setup
Can I change the PDFJS folder location?
Yes: Use viewerFolder attribute:
<ng2-pdfjs-viewer
[viewerFolder]="'/custom-path/pdfjs'"
[pdfSrc]="pdfSrc">
</ng2-pdfjs-viewer>
Important: Ensure path is in angular.json assets:
{
"assets": [
{ "glob": "**/*", "input": "custom-path/pdfjs", "output": "/custom-path/pdfjs" }
]
}
References: #120
How do I disable text layer or annotation layer?
Solution: Use CSS to hide layers:
customCSS = `
.textLayer {
display: none !important;
}
.annotationLayer {
display: none !important;
}
`;
Why: Reduces memory usage and improves performance for large PDFs.
References: #85
🌐 Cross-Browser & Production
Why doesn't PDF load in production (Nginx/IIS) but works locally?
Problem: PDFs work in ng serve but fail in production with 404 or MIME type errors.
Solution: Configure MIME types for .mjs and .ftl files.
Nginx:
http {
types {
application/javascript mjs;
text/plain ftl;
}
}
IIS (web.config):
<staticContent>
<mimeMap fileExtension=".mjs" mimeType="application/javascript" />
<mimeMap fileExtension=".ftl" mimeType="text/plain" />
</staticContent>
References: #276, Installation Guide
Why doesn't fullscreen work in Firefox?
Problem: Fullscreen button doesn't appear or doesn't work in Firefox.
Cause: Browser-specific fullscreen API differences.
Workaround: Ensure fullScreen input is set and test with latest browser:
<ng2-pdfjs-viewer [fullScreen]="true"></ng2-pdfjs-viewer>
References: #111