LWC PDF Generation Examples
Scenario
Generate a PDF from Salesforce record data and store it in Files, with reliable error handling and user feedback.
Example 1: LWC Trigger + Busy State
<template>
<lightning-button
label="Generate PDF"
variant="brand"
onclick={handleGeneratePdf}
disabled={isRunning}>
</lightning-button>
</template>
import { LightningElement, api } from 'lwc';
import generatePdf from '@salesforce/apex/PdfService.generatePdf';
export default class PdfGenerator extends LightningElement {
@api recordId;
isRunning = false;
async handleGeneratePdf() {
this.isRunning = true;
try {
await generatePdf({ recordId: this.recordId });
} finally {
this.isRunning = false;
}
}
}
Example 2: Apex Service + Named Credential
public with sharing class PdfService {
@AuraEnabled
public static Id generatePdf(Id recordId) {
Account a = [SELECT Id, Name, Industry FROM Account WHERE Id = :recordId LIMIT 1];
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:PdfRenderer/v1/render');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setTimeout(120000);
req.setBody(JSON.serialize(new Map<String, Object>{
'template' => 'account-summary',
'payload' => new Map<String, Object>{
'name' => a.Name,
'industry' => a.Industry
}
}));
HttpResponse res = new Http().send(req);
if (res.getStatusCode() != 200) {
throw new CalloutException('PDF render failed: ' + res.getStatusCode());
}
ContentVersion cv = new ContentVersion(
Title = 'Account Summary - ' + a.Name,
PathOnClient = 'account-summary.pdf',
VersionData = res.getBodyAsBlob()
);
insert cv;
return cv.Id;
}
}
Example 3: Test with HttpCalloutMock
@IsTest
private class PdfServiceTest {
private class PdfMock implements HttpCalloutMock {
public HttpResponse respond(HttpRequest req) {
HttpResponse res = new HttpResponse();
res.setStatusCode(200);
res.setBodyAsBlob(Blob.valueOf('fake-pdf-content'));
return res;
}
}
@IsTest
static void generatePdf_createsFile() {
Test.setMock(HttpCalloutMock.class, new PdfMock());
Account a = new Account(Name = 'Acme');
insert a;
Test.startTest();
Id fileId = PdfService.generatePdf(a.Id);
Test.stopTest();
System.assertNotEquals(null, fileId);
}
}
Operational Notes
- Prefer async offload (Queueable) for high-volume PDF generation.
- Include correlation IDs in logs for renderer troubleshooting.
- Avoid embedding sensitive data that is not required by the template.