How to Save a jsPDF Generated PDF From Angular
Create a PDF in an Angular component with jsPDF, download it with doc.save(), or handle the generated bytes as a Blob.

Use jsPDF’s save() method after you create the document. In an Angular component, install jspdf, import jsPDF, add your content, and call doc.save('report.pdf') from a user-triggered method.
import { jsPDF } from 'jspdf';
export class ReportComponent {
downloadPdf(): void {
const doc = new jsPDF();
doc.text('Hello world!', 10, 10);
doc.save('report.pdf');
}
}
This uses jsPDF’s documented client-side API; Angular does not require a separate PDF-saving API. See the jsPDF project and its API documentation.
1. Install jsPDF in your Angular project
Install the package with npm:
npm install jspdf --save
The package includes TypeScript declarations and can be imported like other third-party libraries in Angular projects. Keep the installed version consistent across your development and deployment environments.
2. Create a complete Angular download action
Add a button in the component template and call a method that constructs the PDF only when the user requests it.

<button type="button" (click)="downloadPdf()">
Download report
</button>
import { Component } from '@angular/core';
import { jsPDF } from 'jspdf';
@Component({
selector: 'app-report',
standalone: true,
templateUrl: './report.component.html'
})
export class ReportComponent {
downloadPdf(): void {
const doc = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4'
});
doc.setFontSize(18);
doc.text('Monthly report', 20, 25);
doc.setFontSize(11);
doc.text(`Generated: ${new Date().toLocaleDateString()}`, 20, 35);
doc.text('Revenue increased this month.', 20, 50);
doc.save('monthly-report.pdf');
}
}
save(filename) controls the suggested download name. Generate the document inside the click handler when possible so the browser can associate the download with a user action.
3. Add paragraphs, lines and multiple pages
jsPDF coordinates start at the top-left of the page. The exact page size depends on the format and unit you choose. Track the vertical position and add a page when content reaches the bottom.
import { jsPDF } from 'jspdf';
export class ReportComponent {
downloadPdf(): void {
const doc = new jsPDF({ format: 'a4', unit: 'mm' });
const left = 20;
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const maxTextWidth = pageWidth - left * 2;
const lines = doc.splitTextToSize(
'A long paragraph is wrapped to the available page width. Use this pattern for report text and check the current y position before adding more content.',
maxTextWidth
);
doc.setFontSize(16);
doc.text('Report', left, 25);
doc.setFontSize(11);
let y = 40;
for (const line of lines) {
if (y > pageHeight - 20) {
doc.addPage();
y = 20;
}
doc.text(line, left, y);
y += 6;
}
doc.line(left, y + 2, pageWidth - left, y + 2);
doc.save('wrapped-report.pdf');
}
}
4. Use Blob output when the application needs the PDF bytes
doc.save() is the shortest path to a download. Use doc.output('blob') when you need to upload the PDF, pass it to another API, preview it, or process it before saving.

import { jsPDF } from 'jspdf';
export class ReportComponent {
createPdfBlob(): Blob {
const doc = new jsPDF();
doc.text('Uploadable PDF', 10, 10);
return doc.output('blob');
}
downloadFromBlob(): void {
const blob = this.createPdfBlob();
const url = URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = 'uploadable-report.pdf';
anchor.click();
URL.revokeObjectURL(url);
}
}
For a preview, keep the object URL only as long as needed and call URL.revokeObjectURL(url) during cleanup. The jsPDF API also documents ArrayBuffer and blob URL output modes.
5. Upload a generated PDF with Angular HttpClient
A generated PDF and a PDF returned by a server are separate workflows. After creating a Blob, send it as multipart form data or as the request body required by your backend.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class ReportUploadService {
constructor(private readonly http: HttpClient) {}
upload(pdf: Blob): Observable<unknown> {
const form = new FormData();
form.append('file', pdf, 'report.pdf');
return this.http.post('/api/reports', form);
}
}
When Angular receives a PDF from an HTTP endpoint, configure the response type explicitly:
this.http.get('/api/report.pdf', { responseType: 'blob' });
this.http.get('/api/report.pdf', { responseType: 'arraybuffer' });
Those HttpClient options apply to server responses; they do not replace doc.save() for a document jsPDF just generated in the browser. See Angular’s HTTP request documentation.
6. Common jsPDF options
| Option | Purpose | Example |
|---|---|---|
orientation |
Page direction | 'portrait' or 'landscape' |
unit |
Coordinate unit | 'mm', 'pt', 'px' |
format |
Page size | 'a4', 'letter', or a custom array |
putOnlyUsedFonts |
Reduce unused font data | Set according to your document and installed version |
Choose a unit and page format before laying out coordinates. If you change either later, recalculate margins, wrapping widths and page-break thresholds.
7. Images, fonts and user input
Images must be available in a format and origin the browser can read. Cross-origin restrictions can prevent an image from being embedded. For custom fonts, follow the current jsPDF font and VFS documentation rather than copying a configuration intended for another version.
Sanitize untrusted values before passing them to jsPDF. The project documentation states: “We strongly advise you to sanitize user input before passing it to jsPDF!” This includes text assembled from form fields, imported records and query parameters.
8. Troubleshooting
“Cannot find module ‘jspdf’”
Cause: The dependency is not installed in the workspace that builds the Angular app.
Fix: Run npm install jspdf --save, confirm it appears in package.json, then restart the development server.
The import fails during the build
Cause: A bundler, TypeScript setting or custom Angular build configuration may not match the package being used.
Fix: Use the documented import { jsPDF } from 'jspdf'; form and inspect the actual Angular builder configuration before adding custom webpack changes. The jsPDF project mentions custom webpack builders for Angular externals as a possible configuration path, not a universal requirement.
The click does nothing
Cause: The method is not bound to the button, an exception occurs while composing the document, or browser code is being invoked during server-side rendering.
Fix: Verify the template event binding, inspect the browser console, and keep window, document and object URL calls inside browser-only code when using SSR or prerendering.
The PDF is blank or missing content
Cause: Content may be placed outside the page bounds, an image may not have loaded, or asynchronous data may not be available when the document is built.
Fix: Await data before calling the PDF method, check coordinates against the selected page size, and only add images after their loading promise resolves.
The download has the wrong filename
Cause: The filename passed to save() is the suggested name.
Fix: Pass the desired name, including the .pdf extension, for example doc.save('invoice-2026-09.pdf').
A Blob URL keeps consuming memory
Cause: Object URLs remain allocated until revoked or the document is unloaded.
Fix: Call URL.revokeObjectURL() after the download or preview no longer needs the URL.
Older browsers fail at runtime
Cause: jsPDF relies on modern browser APIs, and the consulted project documentation does not define a complete browser-version matrix.
Fix: Check the browsers your Angular application supports and add the required polyfills according to your support policy.
9. Performance, reliability and cost considerations
- Generate only on demand instead of rebuilding a large document on every change detection cycle.
- Keep images at the resolution needed for the PDF; very large images increase memory use and output size.
- Split long reports into pages while writing them so the browser does not hold unnecessary intermediate data.
- Use Blob output for uploads and previews, and always revoke temporary object URLs.
- For server-returned files, handle HTTP errors and configure the binary response type explicitly.
- Client-side generation has no jsPDF service charge, but it uses the user’s CPU and memory. A server workflow may be preferable for very large or sensitive reports.
Or skip the browser setup
If your actual goal is to capture a rendered Angular page as an image or PDF, ScreenshotNeo provides a single API request instead of maintaining browser automation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo API documentation for request options. Cookie banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages and failed loads are never billed, and response headers identify the page verdict and billing result. Its MCP server lets AI agents use take_screenshot, get_page_info and capture_pdf. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account.
FAQ
Does Angular need a special jsPDF save service?
No. Import jsPDF and call its documented save() method.
Can I rename the downloaded file?
Yes. Pass the desired filename to doc.save().
When should I use output('blob')?
Use it when another part of your application needs the PDF bytes, such as an upload, preview or custom download flow.
Is responseType: 'blob' required for jsPDF?
No. It is an Angular HttpClient setting for receiving a binary response from a server.
Can I generate the PDF during server-side rendering?
Guard browser-only APIs and verify your SSR setup. Download actions require a browser environment.


