Skip to content

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

  1. Performance

    • Optimize content before generation
    • Use batch processing for multiple PDFs
    • Implement proper error handling
  2. Content Structure

    • Use templates for consistent layouts
    • Separate content from presentation
    • Implement reusable components
  3. Error Handling

    • Implement proper error boundaries
    • Provide user feedback
    • Log errors appropriately
  4. 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>
  );
}

Released under the MIT License.