In modern web development, generating PDFs dynamically can be a crucial feature for many applications, especially when dealing with reports, invoices, or documentation. If you’re working with Salesforce Lightning Web Components (LWC) and need to generate PDFs, jsPDF is a powerful library that you can use. In this blog post, we’ll explore how to use jsPDF to create/generating PDFs within Lightning Web Components (LWC), including various methods and details to help you get started.
What is jsPDF?
jsPDF is a popular JavaScript library that allows you to generate PDF documents directly in the browser. It provides a simple API to create PDFs and add various content such as text, images, lines, and more.
The official website for jsPDF is https://github.com/parallax/jsPDF. This GitHub page provides documentation, source code, and updates for the jsPDF library.
Getting Started with Generating PDFs with jsPDF in Lightning Web Components
1. Setup Your LWC Project
Before diving into jsPDF, ensure you have a Lightning Web Component project setup in Salesforce. If you don’t have one, you can create it using Salesforce CLI:
sfdx force:lightning:component:create –type lwc –componentname generatePDFCmp |
2. Install jsPDF Library
You need to include the jsPDF library in your Lightning Web Component. Since Salesforce does not support direct npm package management in LWC, you’ll need to download jsPDF and upload it as a static resource.
- Download the jsPDF library from the official jsPDF GitHub repository
- Go to Salesforce Setup and search for “Static Resources.”
- Click “New” and upload the jspdf.umd.min.js file. Name it jsPDFLibrary
3. Create the LWC Component
Create your Lightning Web Component files if you haven’t already. Here’s a basic setup:
HTML File (generatePDFCmp.html):
<template>
<lightning-button label="Generate PDF" onclick={generatePDF}>
</lightning-button>
</template>
We have included a Lightning Button named ‘Generate PDF’. when clicked, it generates and downloads the PDF.
JavaScript File (generatePDFCmp.js):
- Import the jsPDF into Component
Imports the URL of the static resource (jsPDF library) using the @salesforce/resourceUrl module. This URL is used to load the jsPDF library in the component.
import jsPDFLibrary from '@salesforce/resourceUrl/jsPDFLibrary';
Imports the loadScript function, which is used to load JavaScript libraries from static resources.
import { loadScript } from 'lightning/platformResourceLoader';
- Use renderedCallBack to call loadScript
renderedCallback() Lifecycle hook that runs when the component is inserted into the DOM. It’s used to load external JavaScript libraries.
loadScript(this, jsPDF): Loads the jsPDF library from the static resource.
jsPDFInitialized = false;
renderedCallback(){
if(!this.jsPDFInitialized){
this.jsPDFInitialized = true;
loadScript(this, jsPDFLibrary).then(() => {
console.log('jsPDF library loaded successfully');
}).catch((error) => {
console.log('Error loading jsPDF library', error);
});
}
}
- Create a instance of jsPDF to generate PDF
generatePDF() {
if(this.jsPDFInitialized){
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.text('Hello world!', 10, 10);
doc.save('sample.pdf');
}
}
The generatePdf() method is executed when the “Generate PDF” button is clicked.
It starts by checking if the jsPDF library is available and loaded. Once confirmed, the method creates an instance of jsPDF, which represents the PDF document to be generated.
doc.text(‘Hello world!’, 10, 10) : Adds text to the PDF at coordinates (10, 10)
doc.save(‘sample.pdf’): Triggers a download of the generated PDF with the filename sample.pdf
This is a basic example for displaying text in a generated PDF using the jsPDF library
import { LightningElement } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
import jsPDFLibrary from '@salesforce/resourceUrl/jsPDFLibrary';
export default class GeneratePDFCmp extends LightningElement {
jsPDFInitialized = false;
renderedCallback() {
if (!this.jsPDFInitialized) {
this.jsPDFInitialized = true;
loadScript(this, JS_PDF)
.then(() => {
console.log('jsPDF library loaded successfully');
})
.catch((error) => {
console.error('Error loading jsPDF library', error);
});
}
}
generatePDF() {
if (this.jsPDFInitialized) {
// Make sure to correctly reference the loaded jsPDF library.
const doc = new window.jspdf.jsPDF();
// Add content to the PDF.
doc.text('Hello PDF!', 10, 10);
// Save the PDF.
doc.save('Sample.pdf');
} else {
console.error('jsPDF library not initialised');
}
}
}
Once you deploy and add the components to a page, clicking the button will trigger the PDF download, and the output will match the screenshot below.
I hope you have an understanding of how to set up jsPDF in LWC components. Now, let’s look at detailed descriptions of some common jsPDF methods that you can use in your LWC to generate and manipulate PDFs.
- text(text, x, y, options)
Adds text to the PDF at the specified coordinates (x, y).
- text: The string of text to add.
- x: The x-coordinate for the starting position of the text.
- y: The y-coordinate for the starting position of the text.
- options (optional): An object containing additional settings such as alignment, font size, and font type.
doc.text('Hello, World!', 10, 10); // Adds "Hello, World!" at position (10, 10)
doc.text('Centred Text', 105, 20, { align: 'center' }); // Adds centered text at position (105, 20)
- save(filename)
Saves the generated PDF to the user’s local file system with the given filename.
filename: The name of the file to save (e.g., ‘document.pdf’).
doc.save('myfile.pdf'); // Saves the PDF as "myfile.pdf"
- addPage([orientation], [format])
Adds a new page to the PDF document. You can specify the page orientation and format.
orientation (optional): The orientation of the page. Can be ‘portrait’ (default) or ‘landscape’.
format (optional): The format of the page. Common formats include ‘a4’, ‘letter’, etc.
doc.addPage(); // Adds a new page with default orientation and format
doc.addPage('landscape', 'a4'); // Adds a new landscape-oriented A4 page
- setFontSize(size)
Sets the font size for text in the PDF.
size: The font size to set (e.g., 16 for 16pt font).
doc.setFontSize(18); // Sets the font size to 18pt
doc.text('Large Text', 10, 30); // Applies the font size to this text
- setFont(fontType, fontStyle)
Sets the font type and style for text
fontType: The type of font (e.g., ‘helvetica’, ‘times’).
fontStyle (optional): The style of the font (e.g., ‘normal’, ‘bold’, ‘italic’).
doc.setFont('helvetica', 'bold'); // Sets font to Helvetica bold
doc.text('Bold Helvetica Text', 10, 40);
- image(imageData, x, y, width, height)
Adds an image to the PDF.
imageData: The data URL of the image (e.g., base64 encoded image data).
x: The x-coordinate for the image placement.
y: The y-coordinate for the image placement.
width: The width of the image.height: The height of the image.
const imageData = 'data:image/jpeg;base64,...'; // Your image data URL
doc.addImage(imageData, 'JPEG', 15, 40, 180, 160); // Adds a JPEG image
- setMargins(left, top, right, bottom)
Sets the margins of the PDF document.
left: The left margin.
top: The top margin.
right: The right margin.bottom: The bottom margin.
doc.setMargins(10, 20, 10, 20);
// Sets margins to 10pt on left/right and 20pt on top/bottom
- setLineWidth(width)
Sets the width of the lines drawn in the PDF.
width: The width of the lines in points.
doc.setLineWidth(2); // Sets the line width to 2pt
doc.rect(10, 10, 50, 50); // Draws a rectangle with the set line width
- rect(x, y, width, height, style)
Draw a rectangle on the PDF.
x: The x-coordinate of the rectangle’s starting point.
y: The y-coordinate of the rectangle’s starting point.
width: The width of the rectangle.
height: The height of the rectangle.style (optional): The style of the rectangle. Can be ‘stroke’ (outline), ‘fill’ (filled), or ‘fillstroke’ (filled and outlined).
doc.rect(10, 50, 100, 50, 'stroke'); // Draws a rectangle with an outline
doc.rect(10, 110, 100, 50, 'fill'); // Draws a filled rectangle
- circle(x, y, radius)
Draw a circle on the PDF.
x: The x-coordinate of the center of the circle.
y: The y-coordinate of the center of the circle.radius: The radius of the circle
doc.circle(50, 150, 20); // Draws a circle with center at (50, 150) and radius 20
These methods allow you to create, style, and manipulate PDF documents directly within your LWC.
You can combine these methods to create complex PDF documents with text, images, shapes, and custom styles. For further customization, refer to the jsPDF documentation for more advanced features and methods.
Example: Generating Account Information PDF
I am now creating an example that includes some methods to generate a PDF with Account information.
generatePDFCmp.html
<template>
<lightning-button label = "Generate PDF" onclick={generatePDF}></lightning-button>
</template>
generatePDFCmp.js
import { LightningElement,wire, api } from 'lwc';
import jsPDFLibrary from '@salesforce/resourceUrl/jsPDFLibrary';
import { loadScript } from 'lightning/platformResourceLoader';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import NAME_FIELD from "@salesforce/schema/Account.Name";
import PHONE_FIELD from "@salesforce/schema/Account.Phone";
import RATING_FIELD from "@salesforce/schema/Account.Rating";
import TYPE_FIELD from '@salesforce/schema/Account.Type';
import WEBSITE_FIELD from '@salesforce/schema/Account.Website';
import INDUSTRY_FIELD from "@salesforce/schema/Account.Industry";
import ANNUAL_REVENUE from '@salesforce/schema/Account.AnnualRevenue'
import BILLING_STREET_FIELD from '@salesforce/schema/Account.BillingStreet';
const fields = [NAME_FIELD, PHONE_FIELD, TYPE_FIELD, WEBSITE_FIELD, BILLING_STREET_FIELD, RATING_FIELD, INDUSTRY_FIELD, ANNUAL_REVENUE];
export default class GeneratePDFCmp extends LightningElement {
jsPDFInitialized = false;
@api recordId;
accountName;
phone;
rating;
type;
website;
industry;
annualRevenue;
billingStreet;
@wire(getRecord, {
recordId: "$recordId",
fields
})
accountData({
data,
error
}) {
if (data) {
console.log('data' + JSON.stringify(data))
this.accountName = getFieldValue(data, NAME_FIELD);
this.phone = getFieldValue(data, PHONE_FIELD);
this.rating = getFieldValue(data, RATING_FIELD);
this.type = getFieldValue(data, TYPE_FIELD);
this.website = getFieldValue(data, WEBSITE_FIELD);
this.industry = getFieldValue(data, INDUSTRY_FIELD);
this.annualRevenue = getFieldValue(data, ANNUAL_REVENUE);
this.billingStreet = getFieldValue(data, BILLING_STREET_FIELD);
} else if (error) {
console.log('Error value parse ' + JSON.stringify(error));
}
}
renderedCallback() {
if (!this.jsPDFInitialized) {
this.jsPDFInitialized = true;
loadScript(this, jsPDFLibrary).then(() => {
console.log('jsPDF library loaded successfully');
}).catch((error) => {
console.log('Error loading jsPDF library', error);
});
}
}
generatePDF() {
if (this.jsPDFInitialized) {
try {
const {
jsPDF
} = window.jspdf;
const doc = new jsPDF();
doc.text('Account Information', 70, 20);
//Image in base64 format
const imgData = 'base64 format Image';
doc.addImage(imgData, 'JPEG', 140, 25, 55, 35);
doc.line(60, 24, 145, 24);
doc.setLineWidth(2);
doc.setFontSize(14)
doc.setFont('arial black');
doc.text('Account Name:', 30, 60);
doc.text('Type:', 30, 70);
doc.text('Industry:', 30, 80);
doc.text('Annual Revenue:', 30, 90);
doc.text('Website:', 30, 100);
doc.text('Billing Street:', 30, 110);
doc.text(this.accountName, 70, 60);
doc.text(this.type, 70, 70);
doc.text(this.industry, 70, 80);
doc.text(this.annualRevenue.toString(), 70, 90);
doc.text(this.website, 70, 100);
doc.text(this.billingStreet, 70, 110);
doc.save('AccountInformation.pdf');
} catch (error) {
console.log('Error in generating PDF', JSON.stringify(error));
}
} else {
console.error('jsPDF library is not loaded');
}
}
}
generatePDFCmp.js-meta.xml
<?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
After adding Lightning Button on the Account Record page
Output
This guide covers ‘Generating PDFs using the jsPDF library in LWC.’ Please share it with your Salesforce friends and colleagues. Feel free to leave comments if you have any questions.
jsPDF worked well for me, but with LWC the UI distorts completely when there are multiple pages of (single) datatable … does it work for you, in above scenario? (A scenario similar to itemised bill)
jsPDF worked well for me, but with LWC the UI distorts completely when there are multiple pages of (single) datatable … does it work for you, in above scenario? (A scenario similar to itemised bill)
Excellent article on using the loadStyle function from the platformResourceLoader module in LWCs! One clarification though, the article states that the renderedCallback is fired when the component is inserted into the DOM. Technically, the connectedCallback fires when the component is inserted into the DOM, and the renderedCallback fires when the component is finished rendering.
how can we add table to it ,which is in my html file