A few weeks ago, I ran into a challenge at work—I needed to generate PDFs from dynamically generated HTML content. Whether it was for invoices, reports, or downloadable documents, the requirement was clear: convert HTML to a well-formatted PDF using JavaScript.

At first, I assumed it would be straightforward, but I quickly realized there were multiple ways to achieve this, each with its own strengths and trade-offs. After testing different libraries and methods, I found the best solutions using jsPDF, html2pdf, and Puppeteer.

In this article, we’ll dive deep into these tools, explore how they work, and walk through step-by-step examples so you can seamlessly integrate HTML-to-PDF conversion into your own projects.

But that’s just the beginning! In upcoming articles, we’ll take a closer look at each library, breaking down their advanced features, customization options, and real-world applications. Whether you need client-side or server-side PDF generation, we’ll help you choose the right approach for your specific needs.

Let’s get started! 🚀

More practice

How to Convert HTML to PDF in JavaScript - Example with Code

Why Convert HTML to PDF?

Converting HTML to PDF is essential for various use cases:

  • Preserving Content Formatting: PDFs maintain the layout and design of your HTML content.
  • Sharing and Printing: PDFs are universally accessible and easy to share or print.
  • Offline Access: Users can save and view PDFs without an internet connection.
  • Compliance and Documentation: Many industries require documents in PDF format for legal or regulatory purposes.
  • Improve Data Security: PDFs can be password-protected and restricted from editing, adding an extra layer of security to sensitive documents.

Understanding HTML to PDF Conversion

Before diving into the code, it’s important to understand how HTML to PDF conversion works in JavaScript. There are three main approaches:

  1. Client-side conversion: This happens entirely in the browser using JavaScript libraries. It’s suitable for simple documents and doesn’t require a server.
  2. Server-side conversion: This uses Node.js or another server-side technology to generate PDFs. It’s better for complex documents or high-volume processing.
  3. Hybrid approach: This combines client-side and server-side techniques for optimal results.

Popular JavaScript Libraries for HTML to PDF Conversion

Here are some widely used JavaScript libraries for converting HTML to PDF:

  1. jsPDF: A lightweight library for generating PDFs.
  2. html2pdf.js: A wrapper around jsPDF and html2canvas for easy HTML to PDF conversion.
  3. Puppeteer: A Node.js library for controlling headless Chrome, ideal for server-side PDF generation.

Step-by-Step Guide to Convert HTML to PDF

Turning HTML into a PDF doesn’t have to be complicated! In this section, we’ll walk through the process step by step, using different tools to make it quick and easy.

Step 1: Set Up Your Project

Let’s start by setting up a Vite project with vanilla JavaScript. Vite provides a fast development environment and optimized build process.

To set up this project from scratch, follow these steps:

  1. Create a new directory for your project
  2. Open a terminal and navigate to your project directory
  3. Initialize a new Vite project:
    • pnpm
      npm create vite@latest html-to-pdf-converter -- --template vanilla
    • npm
      npm create vite@latest html-to-pdf-converter -- --template vanilla
    • yarn
      yarn create vite html-to-pdf-converter --template vanilla
    • bun
      bun create vite@latest html-to-pdf-converter --template vanilla
  4. Change into the project directory: cd html-to-pdf-converter
  5. Install the required dependencies: pnpm install
    If you used a different package manager, replace pnpm with npm, yarn, or bun as needed.

Step 2: Install jsPDF Library

Install the jspdf library using your preferred package manager:


# npm
npm install jspdf
# pnpm
pnpm add jspdf
# yarn
yarn add jspdf
# bun
bun add jspdf

Step 3: Create HTML Content

Modify the existing index.html file in your Vite project to include the content you want to convert to PDF.


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML to PDF</title>
</head>
<body>
  <h1>Hello, World!</h1>
  <p>This is a sample HTML content to be converted into a PDF.</p>
</body>
</html>

Step 4: Convert HTML to PDF Using jsPDF

Open src/main.js and add the following code to convert the HTML content to PDF.


import { jsPDF } from "jspdf";

// Create a new jsPDF instance
const doc = new jsPDF();

// Add HTML content to the PDF
doc.html(document.body, {
  callback: function (doc) {
    // Save the PDF
    doc.save("output.pdf");
  },
  x: 10,
  y: 10,
});

Step 5: Customize the PDF Output

You can customize the PDF by adding margins, fonts, and more:


doc.setFontSize(16);
doc.text("Customized PDF", 10, 20);
doc.setFontSize(12);
doc.text("This PDF has been customized using jsPDF.", 10, 30);

Step 5: Using jsPDF with html2canvas

For more control over the PDF generation process, you can use jsPDF and html2canvas separately. This approach gives you more flexibility but requires more code.

How It Works

  1. Use html2canvas to render the HTML element to a canvas
  2. Create a new jsPDF instance
  3. Convert the canvas to an image
  4. Add the image to the PDF
  5. Save or display the PDF

Implementation

Here’s the core code for converting HTML to PDF using jsPDF with html2canvas:


import { jsPDF } from 'jspdf';
import html2canvas from 'html2canvas';

async function generatePDF() {
  // Get the HTML element
  const element = document.getElementById('content-to-convert');
  
  try {
    // Render the element to a canvas
    const canvas = await html2canvas(element, {
      scale: 2,
      logging: false,
      useCORS: true
    });
    
    // Calculate dimensions
    const imgWidth = 210; // A4 width in mm
    const pageHeight = 297; // A4 height in mm
    const imgHeight = canvas.height * imgWidth / canvas.width;
    
    // Create PDF
    const pdf = new jsPDF('p', 'mm', 'a4');
    
    // Add image to PDF
    const imgData = canvas.toDataURL('image/jpeg', 1.0);
    pdf.addImage(imgData, 'JPEG', 0, 0, imgWidth, imgHeight);
    
    // Save the PDF
    pdf.save('document.pdf');
  } catch (error) {
    console.error('Error generating PDF:', error);
  }
}

Alternative Libraries for HTML to PDF Conversion

While jsPDF is a great tool for generating PDFs, it has its limitations, especially when dealing with complex layouts and styles. Fortunately, there are other powerful libraries like html2pdf and Puppeteer that offer more flexibility and advanced features.

In this section, we’ll explore these alternatives, how they work, and when to use them for the best results.

Using html2pdf.js

The html2pdf.js library provides a straightforward way to convert HTML to PDF. It combines html2canvas for rendering and jsPDF for PDF generation.


# npm
npm install html2pdf.js
# pnpm
pnpm add html2pdf.js
# yarn
yarn add html2pdf.js
# bun
bun add html2pdf.js

How It Works

  1. The library captures the HTML element using html2canvas
  2. It converts the canvas to an image
  3. It adds the image to a PDF document using jsPDF
  4. It saves or displays the PDF

Implementation

Here’s the core code for converting HTML to PDF using html2pdf.js:

Example usage:


import html2pdf from 'html2pdf.js';

function generatePDF() {
  // Get the HTML element
  const element = document.getElementById('content-to-convert');
  
  // Configure options
  const options = {
    margin: 10,
    filename: 'document.pdf',
    image: { type: 'jpeg', quality: 0.98 },
    html2canvas: { scale: 2 },
    jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
  };
  
  // Generate PDF
  html2pdf().from(element).set(options).save();
}

Key Options Explained

  • margin: Sets the margin around the content in the PDF (in mm)
  • filename: The name of the downloaded PDF file
  • image.type: The image format used (jpeg or png)
  • image.quality: The quality of the image (0-1)
  • html2canvas.scale: The scaling factor for rendering (higher values improve quality but increase file size)
  • jsPDF.unit: The measurement unit (mm, cm, in)
  • jsPDF.format: The paper size (a4, letter, etc.)
  • jsPDF.orientation: The page orientation (portrait or landscape)

Using Puppeteer

Puppeteer is a Node.js library that provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It’s an excellent choice for server-side HTML to PDF conversion because it uses the actual Chrome rendering engine, resulting in high-quality PDFs that accurately match what you see in the browser.


# npm
npm install puppeteer
# pnpm
pnpm add puppeteer
# yarn
yarn add puppeteer
# bun
bun add puppeteer

How It Works

  1. The client sends HTML content to a server endpoint
  2. The server uses Puppeteer to launch a headless Chrome instance
  3. Puppeteer loads the HTML content in a virtual browser page
  4. Puppeteer generates a PDF from the page
  5. The server sends the PDF back to the client

Server Implementation

First, you need to set up a Node.js server with Express and Puppeteer:


# npm
npm install express puppeteer

# pnpm
pnpm add express puppeteer

# yarn
yarn add express puppeteer

# bun
bun add express puppeteer


Then, create a server file (e.g., server.js):


import express from 'express';
import puppeteer from 'puppeteer';

const app = express();

// Parse JSON request bodies (built-in middleware)
app.use(express.json({ limit: '50mb' }));

// API endpoint to generate PDF
app.post('/api/generate-pdf', async (req, res) => {
  try {
    const { html } = req.body;
    if (!html) {
      return res.status(400).json({ error: 'HTML content is required' });
    }

    const browser = await puppeteer.launch({
      headless: 'new',
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });

    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });

    const pdf = await page.pdf({
      format: 'A4',
      printBackground: true,
      margin: { top: '20mm', right: '20mm', bottom: '20mm', left: '20mm' }
    });

    await browser.close();

    res.setHeader('Content-Type', 'application/pdf');
    res.setHeader('Content-Disposition', 'attachment; filename=document-puppeteer.pdf');
    res.send(pdf);
  } catch (error) {
    console.error('Error generating PDF:', error);
    res.status(500).json({ error: 'Failed to generate PDF' });
  }
});

// Start the server
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Client Implementation

On the client side, you need to send the HTML content to the server:


async function generatePDFWithPuppeteer() {
  try {
    // Get the HTML content
    const html = document.getElementById('html-content').value;
    
    // Send the HTML to the server
    const response = await fetch('/api/generate-pdf', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ html }),
    });
    
    if (!response.ok) {
      throw new Error('Failed to generate PDF');
    }
    
    // Get the PDF as a blob
    const blob = await response.blob();
    
    // Create a URL for the blob
    const url = URL.createObjectURL(blob);
    
    // Create a link to download the PDF
    const a = document.createElement('a');
    a.href = url;
    a.download = 'document-puppeteer.pdf';
    document.body.appendChild(a);
    a.click();
    
    // Clean up
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  } catch (error) {
    console.error('Error generating PDF with Puppeteer:', error);
    alert('Error generating PDF. Check console for details.');
  }
}

Advanced Customization Options

Sometimes, just converting HTML to PDF isn’t enough—you might need more control over the final output. Whether it’s customizing page layouts, adding headers and footers, tweaking margins, or embedding fonts, advanced customization options can make a huge difference.

To keep things concise, this section will focus specifically on jsPDF’s customization features, helping you fine-tune your PDFs with precision.

Custom Fonts

You can add custom fonts to your PDF using jsPDF:


import { jsPDF } from 'jspdf';

function addCustomFont() {
  const pdf = new jsPDF();
  
  // Add a custom font
  pdf.addFont('fonts/OpenSans-Regular.ttf', 'OpenSans', 'normal');
  
  // Use the custom font
  pdf.setFont('OpenSans');
  pdf.setFontSize(16);
  pdf.text('This text uses a custom font', 20, 20);
  
  pdf.save('custom-font-document.pdf');
}

Page Headers and Footers

Adding headers and footers to each page:


function addHeadersAndFooters() {
  const pdf = new jsPDF();
  const pageCount = 5; // Example: 5 pages
  
  // Add content to each page
  for (let i = 1; i <= pageCount; i++) {
    if (i > 1) pdf.addPage();
    
    // Add header
    pdf.setFontSize(10);
    pdf.setTextColor(100, 100, 100);
    pdf.text('Company Name - Confidential', 105, 10, { align: 'center' });
    
    // Add page content
    pdf.setFontSize(12);
    pdf.setTextColor(0, 0, 0);
    pdf.text(`Page ${i} Content`, 20, 30);
    
    // Add footer
    pdf.setFontSize(10);
    pdf.setTextColor(100, 100, 100);
    pdf.text(`Page ${i} of ${pageCount}`, 105, 287, { align: 'center' });
  }
  
  pdf.save('document-with-headers-footers.pdf');
}

Tables

For complex tables, you can use jsPDF’s autoTable plugin:


import { jsPDF } from 'jspdf';
import 'jspdf-autotable';

function generateTablePDF() {
  const pdf = new jsPDF();
  
  // Define table data
  const tableData = [
    ['Name', 'Email', 'Country', 'Age'],
    ['John Doe', 'john@example.com', 'USA', '38'],
    ['Jane Smith', 'jane@example.com', 'Canada', '45'],
    ['Bob Johnson', 'bob@example.com', 'UK', '29'],
    ['Alice Brown', 'alice@example.com', 'Australia', '32']
  ];
  
  // Generate table
  pdf.autoTable({
    head: [tableData[0]],
    body: tableData.slice(1),
    startY: 20,
    styles: {
      fontSize: 12,
      cellPadding: 5,
      overflow: 'linebreak',
      halign: 'center'
    },
    headStyles: {
      fillColor: [41, 128, 185],
      textColor: 255
    },
    alternateRowStyles: {
      fillColor: [240, 240, 240]
    }
  });
  
  pdf.save('table-document.pdf');
}

CSS Support

When using html2canvas, you can include CSS styles in your HTML:


function generateStyledPDF() {
  // Create a container with styled content
  const element = document.createElement('div');
  element.innerHTML = `
    <style>
      .pdf-container {
        font-family: Arial, sans-serif;
        padding: 20px;
      }
      .pdf-header {
        color: #2563eb;
        border-bottom: 2px solid #2563eb;
        padding-bottom: 10px;
      }
      .pdf-content {
        margin-top: 20px;
      }
      .pdf-table {
        width: 100%;
        border-collapse: collapse;
        margin-top: 20px;
      }
      .pdf-table th, .pdf-table td {
        border: 1px solid #ddd;
        padding: 8px;
      }
      .pdf-table th {
        background-color: #f1f5f9;
      }
    </style>
    <div class="pdf-container">
      <h1 class="pdf-header">Styled Document</h1>
      <div class="pdf-content">
        <p>This document includes CSS styling that will be captured in the PDF.</p>
        <table class="pdf-table">
          <thead>
            <tr>
              <th>Item</th>
              <th>Description</th>
              <th>Price</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Item 1</td>
              <td>Description of item 1</td>
              <td>$100.00</td>
            </tr>
            <tr>
              <td>Item 2</td>
              <td>Description of item 2</td>
              <td>$150.00</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  `;
  
  document.body.appendChild(element);
  
  // Generate PDF with styles
  html2pdf().from(element).save().then(() => {
    document.body.removeChild(element);
  });
}

Comparing the Three Methods

Let’s now compare the three popular tools for converting HTML to PDF: jsPDF, html2pdf, and Puppeteer. This will help you choose the best option for your project.

Featurehtml2pdf.jsjsPDF + html2canvasPuppeteer
EnvironmentClient-sideClient-sideServer-side
Setup ComplexityLowMediumHigh
Rendering QualityGoodGoodExcellent
CSS SupportLimitedLimitedFull
JavaScript SupportLimitedLimitedFull
PerformanceDepends on browserDepends on browserConsistent
File SizeCan be largeCan be largeOptimized
Best ForSimple documentsMedium complexityComplex layouts

Conclusion

In this guide, we explored three powerful tools for converting HTML to PDF: jsPDF, html2pdf, and Puppeteer. Each method comes with its own strengths—jsPDF is great for client-side PDF generation, html2pdf offers an easy way to convert entire HTML elements, and Puppeteer provides a robust server-side solution for handling complex layouts.

Choosing the right tool depends on your specific needs, whether it’s generating lightweight PDFs in the browser or creating high-quality documents on the server. As you integrate these solutions into your projects, don’t hesitate to experiment with their customization options to achieve the perfect output.

In upcoming articles, we’ll take a deeper dive into each library, exploring their advanced features and capabilities to help you make the most of them.