Salesforce Custom PDF Generation Using LWC and HTML-to-Canvas (No Visualforce)

Introduction
Generating PDFs in Salesforce is often tied to Visualforce and the renderAs=”PDF” attribute — a solution that feels outdated and limited in design flexibility. If you’ve ever tried to implement modern styling, responsive layouts, or dynamic visuals in Visualforce PDFs, you know the pain.
In this blog, written from the perspective of a Salesforce consultant in USA, we’ll explore how to build a completely custom PDF engine using Lightning Web Components, with the help of open-source libraries like html2canvas and jsPDF, enabling you to generate pixel-perfect PDFs without Apex or Visualforce.
This method is:
- Modern — full CSS3/HTML5 compatibility
- Lightweight — no server-side rendering or limits
- Fully client-side — fast, interactive, and flexible
Implementation Details
1. Static Resources Setup
First, upload the following JS libraries as static resources:
- html2canvas.js: to convert HTML to image
- jspdf.umd.min.js: to export the image as PDF
2. LWC Structure
Folder: lwc/pdfGenerator
pdfGenerator.js
html
<template>
<lightning-card title=”Invoice Generator”>
<div class=”slds-p-around_medium”>
<div id=”pdf-content” class=”pdf-box”>
<h1 style=”color:#0f395f;”>Invoice</h1>
<p><strong>Customer:</strong> John Doe</p>
<p><strong>Amount:</strong> ₹12,000</p>
<p><strong>Date:</strong> 14 July 2025</p>
<p><strong>Service:</strong> Website development</p>
</div>
<lightning-button label=”Generate PDF” onclick={handleGeneratePdf} variant=”brand”></lightning-button>
</div>
</lightning-card>
</template>
pdfGenerator.js
js
import { LightningElement } from ‘lwc’;
import html2canvas from ‘@salesforce/resourceUrl/html2canvas’;
import jsPDF from ‘@salesforce/resourceUrl/jspdf’;
import { loadScript } from ‘lightning/platformResourceLoader’;
export default class PdfGenerator extends LightningElement {
html2canvasInitialized = false;
jsPdfInitialized = false;
renderedCallback() {
if (this.html2canvasInitialized && this.jsPdfInitialized) return;
Promise.all([
loadScript(this, html2canvas),
loadScript(this, jsPDF)
])
.then(() => {
this.html2canvasInitialized = true;
this.jsPdfInitialized = true;
})
.catch(error => {
console.error(‘Failed to load libraries’, error);
});
}
handleGeneratePdf() {
const content = this.template.querySelector(‘#pdf-content’);
window.html2canvas(content).then(canvas => {
const imgData = canvas.toDataURL(‘image/png’);
const pdf = new window.jspdf.jsPDF(‘p’, ‘mm’, ‘a4’);
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, ‘PNG’, 0, 0, pdfWidth, pdfHeight);
pdf.save(‘Invoice.pdf’);
});
}
}
xml
pdfGenerator.js-meta.xml
<?xml version=”1.0″ encoding=”UTF-8″ ?>
<LightningComponentBundle xmlns=”http://soap.sforce.com/2006/04/metadata”>
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
Conclusion
This modern PDF generation method in Salesforce using LWC and client-side JS libraries offers far more design freedom, speed, and interactivity compared to traditional Visualforce-based solutions. It enables:
- Full HTML/CSS control
- Brand-styled invoices and documents
- Exporting PDFs without hitting Apex governor limits
Whether you’re building quotes, invoices, certificates, or custom reports — this approach provides a scalable, beautiful alternative to Visualforce, and keeps your UI fully in the Lightning Experience.
related blog


