Loading Documents
Everything about getting a PDF into the viewer: the source formats pdfSrc accepts, controlling the initial view, authenticated loading with custom headers, password-protected documents, and the loading/error UX.
Document Sources
The pdfSrc input accepts three source types: a URL string, a Blob, or a Uint8Array.
URL
The simplest case — point the viewer at a file the browser can reach:
<ng2-pdfjs-viewer pdfSrc="assets/sample.pdf"></ng2-pdfjs-viewer>
Absolute URLs work too (subject to CORS, like any cross-origin fetch):
<ng2-pdfjs-viewer pdfSrc="https://example.com/reports/q3.pdf"></ng2-pdfjs-viewer>
Blob
Useful when your API returns the PDF bytes — fetch with HttpClient and hand the viewer the blob:
export class MyComponent {
@ViewChild('pdfViewer') pdfViewer!: PdfJsViewerComponent;
constructor(private http: HttpClient) {}
openFromServer() {
this.http
.get('/api/documents/42', { responseType: 'blob' })
.subscribe((blob: Blob) => {
this.pdfViewer.pdfSrc = blob;
this.pdfViewer.refresh();
});
}
}
When you change pdfSrc programmatically after the viewer has rendered, call refresh() to load the new document.
Uint8Array
Raw bytes work the same way — generated PDFs, IndexedDB content, decrypted buffers:
const bytes: Uint8Array = await this.generatePdf();
this.pdfViewer.pdfSrc = bytes;
this.pdfViewer.refresh();
Initial View State
Control what the user sees when the document opens:
<ng2-pdfjs-viewer
pdfSrc="assets/sample.pdf"
[page]="5"
[zoom]="'page-width'"
[rememberLastView]="false">
</ng2-pdfjs-viewer>
[page]— the page to open on. Also settable after load (pdfViewer.page = 5).[zoom]— initial zoom level. Supportsauto(default),page-fit,page-width,page-actual, and percentage values like'150%'. Two-way bindable with[(zoom)].[namedDest]— jump to a named destination defined inside the PDF instead of a page number:
<ng2-pdfjs-viewer pdfSrc="assets/manual.pdf" namedDest="chapter3"></ng2-pdfjs-viewer>
[rememberLastView]— restore the previous reading position (page/zoom/sidebar) when the same document is reopened. Defaults totrue. Set it tofalseif documents should always open at page 1 / your configured initial view.
Authenticated Loading
The viewer runs inside an iframe, and an iframe's own request for a URL cannot carry custom headers. The component solves this with httpHeaders: when set, the component fetches the document itself (with your headers) and feeds the viewer a local blob — the URL never has to be reachable by the iframe directly.
export class MyComponent {
headers = { Authorization: `Bearer ${this.auth.token}` };
onProgress(progress: { loaded: number; total: number }) {
// total is 0 when the server sends no Content-Length
this.percent = progress.total
? Math.round((progress.loaded / progress.total) * 100)
: null;
}
}
<ng2-pdfjs-viewer
[pdfSrc]="protectedUrl"
[httpHeaders]="headers"
[withCredentials]="true"
(onProgress)="onProgress($event)">
</ng2-pdfjs-viewer>
[httpHeaders]— aRecord<string, string>of request headers (JWT bearer tokens, API keys) sent with the component-side fetch of a stringpdfSrcURL.[withCredentials]— send cookies/credentials with that fetch (defaultfalse).(onProgress)—{ loaded, total }download progress, emitted only for this component-side fetch path.
:::info S3 and signed URLs
If your storage supports pre-signed URLs (S3, Azure Blob SAS, GCS), you don't need httpHeaders at all — the credentials live in the URL itself. Just pass the signed URL as pdfSrc and let the viewer load it directly. This also keeps PDF.js's streaming/range-request loading, which the header-based fetch path gives up (see Large Documents below).
:::
Password-Protected PDFs
No extra configuration needed: when a document is password-protected, the viewer shows PDF.js's built-in password dialog. The component fires (onPasswordPrompt) at that moment — and automatically drops its own loading spinner so the dialog is usable. Use the event to tear down any overlays or skeletons your app put on top:
<ng2-pdfjs-viewer
pdfSrc="assets/confidential.pdf"
(onPasswordPrompt)="hideAppOverlay()">
</ng2-pdfjs-viewer>
Loading UX
A loading spinner is shown by default ([showSpinner]="true"). Replace it with your own Angular template:
<ng-template #loadingTpl>
<div class="loading">
<div class="spinner"></div>
<p>Loading your document...</p>
</div>
</ng-template>
<ng2-pdfjs-viewer
pdfSrc="assets/sample.pdf"
[customSpinnerTpl]="loadingTpl">
</ng2-pdfjs-viewer>
Error Handling
When a document fails to load, (onDocumentError) fires with a DocumentError ({ message, source?, name? }). You can also shape the message the user sees:
<ng-template #errorTpl>
<div class="error">
<h3>Couldn't load this document</h3>
<p>Please check your connection and try again.</p>
<button (click)="retry()">Retry</button>
</div>
</ng-template>
<ng2-pdfjs-viewer
[pdfSrc]="src"
[customErrorTpl]="errorTpl"
(onDocumentError)="logError($event)">
</ng2-pdfjs-viewer>
errorMessage— your custom error text.errorOverride— replace the default error message entirely witherrorMessage(defaultfalse).errorAppend— appenderrorMessageto the default message (defaulttrue).customErrorTpl— full Angular template control over the error state (witherrorClassfor styling).
Large Documents
PDF.js can stream documents with HTTP range requests, so the first pages render before the whole file downloads. Two things make that work:
- Linearize the PDF ("fast web view") when producing it, e.g.
qpdf --linearize input.pdf output.pdf. - Serve with range support — the server must send
Accept-Ranges: bytesand honorRangerequests (standard on Nginx/IIS/S3/CDNs; check that proxies don't strip it).
Pages render lazily as the user scrolls, so memory stays bounded even for thousand-page documents. Note that the httpHeaders/withCredentials path downloads the full document before display (headers can't be attached to the viewer's streaming fetch) — prefer time-limited signed URLs for very large protected documents. See the "Large Documents & Fast Web View" section of the README for the full recipe.