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


NSIQ Icon
July 23, 2025

salesforce custom pdf generation

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.