Convert HTML to PDF in JavaScript

30 June 2025
This post thumbnail

There is usually no lack of Javascript libraries for any given problem. But to my surprise, there's not that many options for HTML to PDF conversion in Javascript. I did manage to find and test a few packages that looked promising and have reviewed them here.

By the end of this guide you should have a good idea of which option would work best for your use case. At the bottom of the page there's also a table that recaps all of my findings.

tl;dr Puppeteer for quality, jsPDF for ease of use

The good news is that the best option for HTML to PDF conversion across all programming languages is Puppeteer, which is a Javascript first library. Puppeteer uses a headless Chrome browser under the hood which can render any HTML, CSS or Javascript that you throw at it. The downside is that it's resource heavy.

For a more lightweight alternative with less complicated pages, I had the best results with jsPDF. jsPDF runs clientside, which depending on your use case might be an advantage or a disadvante.

Puppeteer

Puppeteer is a Javascript library which allows you to control a headless Chrome (or Firefox) instance using a nice API.

It essentially allows you to automate anything that you can do "manually" in the browser. And one thing you can always do manually in a browser is print HTML webpages to a PDF file. With Puppeteer we can automate this using Javascript.

Installing it is straightforward with npm:

npm install puppeteer

When installing it, Puppeteer will also download a recent version of Chrome.

Here's how to generate a PDF from a URL:

const puppeteer = require('puppeteer');

async function generatePDF() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Navigate to URL
  await page.goto('https://transformy.io/guides/', {
    waitUntil: 'networkidle2'
  });
  
  // Generate PDF
  await page.pdf({
    path: 'transformy_guides.pdf',
    format: 'A4',
    printBackground: true
  });
  
  await browser.close();
}

generatePDF();

You can also generate PDFs from HTML strings:

async function generatePDFFromHTML() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  const html = '' # add your html here
  
  await page.setContent(html);
  
  await page.pdf({
    path: 'invoice.pdf',
    format: 'A4',
  });
  
  await browser.close();
}

Puppeteer really shines with complicated HTML or Javascript rich pages. One thing that you can do is wait until a specific part of the page has finished loading before you generate the PDF.

// Wait for JS content to finish loading
await page.waitForSelector('.charts-container');
await page.pdf({ path: 'charts-report.pdf' });

This is just one simple example but it shows how far you can push things with Puppeteer and the headless browser powering it. It does come with a cost though: it's slower than many other solutions and scaling this to support large numbers of (paralel) PDF conversions comes with a lot of hassle.

jsPDF

jsPDF is a client-side PDF generation library. It's not specifically developed for HTML to PDF conversion, but, together with html2canvas, it can be used to do exactly that.

Here's how to install both libraries:

npm install jspdf
npm install html2canvas

There are essentially two steps to converting HTML to PDF with this setup. First, you convert the html file or string to a canvas using html2canvas. Next you add that canvas to the PDF and you specify the position.

Here's how:

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

// Get the element you want to convert
const element = document.getElementById("invoice-container");

html2canvas(element).then((canvas) => {
  const imgData = canvas.toDataURL("image/png");
  const pdf = new jsPDF();
  
  const imgWidth = 210; // A4 width in mm
  const pageHeight = 297; // A4 height in mm
  const imgHeight = (canvas.height * imgWidth) / canvas.width;
  let heightLeft = imgHeight;
  
  let position = 0;
  
  pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
  heightLeft -= pageHeight;

  pdf.save("invoice.pdf");
});

It's quite straightforward, but if the generated canvas doesn't fit the size of your PDF you need to start fiddling until it does.

When you want to convert to a multi-page PDF, you need to calculate where the different pages start/stop:

// Add new pages if content is longer than one page
while (heightLeft >= 0) {
  position = heightLeft - imgHeight;
  pdf.addPage();
  pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight);
  heightLeft -= pageHeight;
}

The fact that jsPDF can run in the browser is really conveniant and it makes it a good option if that's something you need. But, the process boils down to taking a screenshot of your content and printing it and as you might image, that can come with hickups.

html2pdf.js

html2pdf.js is a wrapper library that combines html2canvas and jsPDF, making both installation and usage smoother. Whereas jsPDF is a general PDF generation tool, this one focuses on HTML to PDF conversion only.

Installation is just one line:

npm install html2pdf.js

The great thing about it is the API. It doesn't get much easier than this:

import html2pdf from 'html2pdf.js';

var element = document.getElementById('content-container');
html2pdf(element);

You can also configure it with a bunch of options:

const opt = {
  margin:       1,
  filename:     'transformy-innvoice.pdf',
  image:        { type: 'jpeg', quality: 0.98 },
  html2canvas:  { scale: 2 },
  jsPDF:        { unit: 'in', format: 'letter', orientation: 'portrait' }
};

html2pdf().set(opt).from(element).save();

If you need something that runs in the browser, this is a nicer option than directly using jsPDF and html2canvas. But it still comes with the same cons and the number of real world use cases for this is limited.

node-wkhtmltopdf

wkhtmltopdf is a very popular HTML to PDF command line tool. There's an equally popular Python wrapper for it, and there is one for Javascript too.

It doesn't get talked about much in the Javascript community though. That's likely because wkhtmltopdf isn't actively maintained anymore. The command line tool is built on top of the Qt Webkit rendering engine which also isn't actively maintained.

The Javascript wrapper node-wkhtmltopdf hasn't been updated in a few years and that might scrare people off, but since the underlying library hasn't changed in the same time, that shouldn't be too surprising. It still works as expected and it is worth considering.

Before you can use the package, you first need to install wkhtmltopdf on your system. I've written about how to do that in detail in my wkhtmltopdf tutorial. Once you've done that, you can install the node wrapper:

npm install wkhtmltopdf

The wrapper comes with an easy to use API: wkhtmltopdf(source, [options], [callback]).

First add the library:

var wkhtmltopdf = require('wkhtmltopdf');

Here's how you can generate a PDF from a URL:

wkhtmltopdf('http://transformy.io/guides/', { pageSize: 'letter', output: 'transformy.pdf' })

Or from an HTML string:

wkhtmltopdf('<h1>Hello transformy</h1>', { pageSize: 'letter', output: 'transformy.pdf' })

node-wkhtmltopdf also accepts all the additional configuration options that the command line tool does which allow for a lot of customization.

Since the underlying library and rendering engine are no longer maintaned, this won't work very well with the latest CSS and Javascript. But it is a real workhorse for a lot of more simple usecases and I recommend giving it a try.

Conclusion

Here's a comparison table with a recap of all the libraries that I reviewed in this article.

LibraryEnvironmentBest ForSpeedLearn More
PuppeteerNode.jsPerfect rendering, complex sites, JavaScript-heavy pagesSlowPuppeteer docs
jsPDFBrowserSimple PDFs, client-side, basic documentsFastjsPDF docs
html2pdf.jsBrowserSimple PDFs, client-side, basic documentsFasthtml2pdf.js docs
node-wkhtmltopdfNode.jsHTML with basic CSS and Javascript support, when you need a lightweight backend optionMediumwkhtmltopdf docs

As I mentioned in the beginning of the article, you'll get the highest quality results using Puppeteer and wkhtmltopdf is pretty good if you need something more lightweight. jsPDF is a great option if you want something that can run in the browser.

Let me know which one you go with or if you discover anything I missed.