Programmatic Mode
Programmatic Mode allows you to generate PDFs dynamically without rendering components to the screen. This guide explains how to use Programmatic Mode effectively.
Overview
Programmatic Mode is ideal when you want to:
- Generate PDFs on the server
- Create PDFs from dynamic data
- Generate multiple PDFs in batch
- Create PDFs without visual rendering
Basic Usage
tsx
import React from "react";
import { useEasyPdf } from "@easypdf/react";
function ProgrammaticPDFGenerator() {
const { createPDFBlob, downloadPDF, isCreatingBlob } = useEasyPdf();
const generatePDF = async () => {
const content = (
<div>
<h1>Generated PDF</h1>
<p>This content is generated programmatically.</p>
</div>
);
try {
const blob = await createPDFBlob(content, {
filename: "generated.pdf",
});
await downloadPDF(blob);
} catch (error) {
console.error("Failed to generate PDF:", error);
}
};
return (
<button onClick={generatePDF} disabled={isCreatingBlob}>
{isCreatingBlob ? "Generating..." : "Generate PDF"}
</button>
);
}
Dynamic Content Generation
Data-Driven PDFs
tsx
function DataDrivenPDF() {
const { createPDFBlob, downloadPDF } = useEasyPdf();
const generateReport = async (data) => {
const content = (
<div>
<h1>Data Report</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{data.map((item, index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</div>
);
const blob = await createPDFBlob(content, {
filename: "report.pdf",
});
await downloadPDF(blob);
};
return <button onClick={() => generateReport(data)}>Generate Report</button>;
}
Template-Based Generation
tsx
function PDFTemplate({ title, content, footer }) {
return (
<div className="pdf-template">
<style>
{`
.pdf-template {
font-family: Arial, sans-serif;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.content {
margin: 20px 0;
}
.footer {
margin-top: 30px;
text-align: center;
font-size: 12px;
}
`}
</style>
<div className="header">
<h1>{title}</h1>
</div>
<div className="content">{content}</div>
<div className="footer">{footer}</div>
</div>
);
}
function TemplateBasedGenerator() {
const { createPDFBlob, downloadPDF } = useEasyPdf();
const generateFromTemplate = async (data) => {
const content = (
<PDFTemplate
title={data.title}
content={data.content}
footer={data.footer}
/>
);
const blob = await createPDFBlob(content);
await downloadPDF(blob);
};
return (
<button onClick={() => generateFromTemplate(data)}>Generate PDF</button>
);
}
Batch Processing
Generate multiple PDFs in sequence:
tsx
function BatchPDFGenerator() {
const { createPDFBlob } = useEasyPdf();
const generateBatch = async (items) => {
const blobs = await Promise.all(
items.map(async (item) => {
const content = (
<div>
<h1>{item.title}</h1>
<p>{item.content}</p>
</div>
);
return createPDFBlob(content, {
filename: `${item.id}.pdf`,
});
})
);
return blobs;
};
return <button onClick={() => generateBatch(items)}>Generate Batch</button>;
}
Configuration
Global Configuration
tsx
const { createPDFBlob } = useEasyPdf({
pageSize: "A4",
margins: {
top: 20,
right: 20,
bottom: 20,
left: 20,
},
styles: {
backgroundColor: "#ffffff",
defaultFontSize: 12,
defaultFontFamily: "Arial, sans-serif",
},
});
Per-Generation Configuration
tsx
const blob = await createPDFBlob(content, {
filename: "document.pdf",
pageSize: "A4",
watermark: {
text: "CONFIDENTIAL",
opacity: 0.2,
},
header: {
text: "Company Report",
fontSize: 12,
},
footer: {
text: "Page {pageNumber} of {totalPages}",
fontSize: 10,
},
});
Error Handling
tsx
function PDFGeneratorWithErrorHandling() {
const { createPDFBlob, downloadPDF } = useEasyPdf();
const [error, setError] = useState(null);
const generatePDF = async () => {
try {
setError(null);
const blob = await createPDFBlob(content);
await downloadPDF(blob);
} catch (err) {
setError(err.message);
console.error("PDF generation failed:", err);
}
};
return (
<div>
{error && <div className="error">{error}</div>}
<button onClick={generatePDF}>Generate PDF</button>
</div>
);
}
Best Practices
Performance
- Optimize content before generation
- Use batch processing for multiple PDFs
- Implement proper error handling
Content Structure
- Use templates for consistent layouts
- Separate content from presentation
- Implement reusable components
Error Handling
- Implement proper error boundaries
- Provide user feedback
- Log errors appropriately
Configuration
- Use global config for common settings
- Override specific settings as needed
- Validate configuration values
Examples
Invoice Generator
tsx
function InvoiceGenerator() {
const { createPDFBlob, downloadPDF } = useEasyPdf();
const generateInvoice = async (invoiceData) => {
const content = (
<div className="invoice">
<style>
{`
.invoice {
padding: 20px;
font-family: Arial, sans-serif;
}
.invoice-header {
text-align: center;
margin-bottom: 30px;
}
.invoice-details {
margin: 20px 0;
}
.invoice-table {
width: 100%;
border-collapse: collapse;
}
.invoice-table th,
.invoice-table td {
border: 1px solid #ddd;
padding: 8px;
}
`}
</style>
<div className="invoice-header">
<h1>Invoice #{invoiceData.id}</h1>
<p>Date: {invoiceData.date}</p>
</div>
<div className="invoice-details">
<h2>Bill To:</h2>
<p>{invoiceData.customer.name}</p>
<p>{invoiceData.customer.address}</p>
</div>
<table className="invoice-table">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{invoiceData.items.map((item, index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.quantity}</td>
<td>${item.price}</td>
<td>${item.quantity * item.price}</td>
</tr>
))}
</tbody>
<tfoot>
<tr>
<td colSpan="3">Total</td>
<td>${invoiceData.total}</td>
</tr>
</tfoot>
</table>
</div>
);
const blob = await createPDFBlob(content, {
filename: `invoice-${invoiceData.id}.pdf`,
watermark: {
text: "PAID",
opacity: 0.2,
},
});
await downloadPDF(blob);
};
return (
<button onClick={() => generateInvoice(data)}>Generate Invoice</button>
);
}