A very common requirement for web applications is a way to generate PDFs and make them available for download. This is typically to produce invoices, tickets, sales contracts, reports, and other documents personalized with customer data.

In this article, we walk you through a simple, open-source method: html2pdf.js. This JavaScript library embeds in a website to make parts of it downloadable as PDFs. For this guide, we show how to generate PDFs in a web application from an HTML template. At the end, we also consdier a JavaScript method for generating PDFs from MS Office file templates that will eliminate reliance on dev resources for template creation and maintenance, and doesn't require server-based conversion.

How to Create a PDF from HTML with html2pdf.js

The html2pdf.js library relies on pure JavaScript. As a result, html2pdf embeds directly client-side, in the browser. And unlike using the browser print function, html2pdf enables you to create an authentic download experience for your users. It works behind your interface and seems like a natural part of your web app.

How html2pdf.js Works

Combining html2canvas and jsPDF, html2pdf relies on a simple workaround to bypass typical challenges associated with converting HTML to PDF in a browser. First, it uses html2canvas to convert your HTML to a canvas and renders that canvas to a static image. It is then easy for jsPDF to wrap the new image in a PDF file, made downloadable to your users.

Getting Started

We’ve provided a manually typed HTML invoice template to use with this guide, but you can easily generate HTML for your own document in a backend.

Installation

Html2pdf.js installs in three main ways: via HTML, by NPM, or by inserting the library using JavaScript.

HTML

The simplest way to install html2pdf.js is to download dist/html2pdf.bundle.min.js to your project folder and include it in your HTML with the following:

<script  src="html2pdf.bundle.min.js"></script>

NPM

You can also install html2pdf.js and its dependencies using NPM:

npm install --save html2pdf.js

JavaScript (Console)

Alternatively, if you’re on a web page you can’t modify directly and wish to use html2pdf.js for screenshot capture, paste the following into the console:

function addScript(url) {
  const script = document.createElement('script');
  script.type = 'application/javascript';
  script.src = url;
  document.head.appendChild(script);
}
addScript('https://raw.githack.com/eKoopmans/html2pdf/master/dist/html2pdf.bundle.js');

Basic Usage

Once html2pdf.js is installed, you can use it. The following code grabs and converts a selection of HTML, and then prompts the user to “save”.

const element = document.querySelector('body');
html2pdf(element);

Our example invoice then displays as such when opened:

Advanced Usage

If called without arguments, html2pdf.js returns a worker object. This worker in turn supports several methods and arguments. The library’s new Promise-based API lets you chain methods sequentially, insert your own intermediate steps, or skip steps without difficulty.

For this guide, we won’t do anything fancy, instead sticking to the default flow:

// This will implicitly create the canvas and PDF objects before saving.
const worker = html2pdf().from(element).save();
// The basic workflow of html2pdf.js tasks (enforced by the prereq system) is:
// .from() -> .toContainer() -> .toCanvas() -> .toImg() -> .toPdf() -> .save()

Optional Parameter

In addition, html2pdf.js accepts an optional parameter with settings to control how the final PDF file displays and the to-image workaround used for conversion.

const element = document.querySelector('body');
const opt = {
  filename: 'myPage.pdf',
  margin: 2,
  image: {type: 'jpeg', quality: 0.9},
  jsPDF: {format: 'letter', orientation: 'portrait'}
};
// New Promise-based usage:
html2pdf().set(opt).from(element).save();
// Old monolithic-style usage:
html2pdf(element, opt);

Page-break Examples

Lastly, we can automatically add page breaks to our PDFs to control how the HTML content is split. Page breaks can be added via CSS styles, selectors on individual elements, or avoided (via the avoid-all mode). Here is the page break function in action:

// Avoid page-breaks on all elements, and add one before #pageX.
html2pdf().set({
  pagebreak: {mode: 'avoid-all', before:'#pageX'}
});
// Adds page-breaks according to the CSS break-before, break-after, and break-inside properties.
// Only recognizes always/left/right for before/after, and avoid for inside.
html2pdf().set({
  pagebreak: {mode: 'css' }
});

Short invoices don’t require page breaks. But you are required to add breaks on longer documents or documents with complex content, such as those with large images and tables, due to browser limits on how big canvases can get. (html2pdf uses a single canvas when creating each page.)

Further Considerations

html2pdf.js works fine with content with a simple layout, limited to one page, or that otherwise does not require interactive features. There are a few issues identified by the open-source community to consider, as these complicate some projects. Based on our research, here are potentially the most significant:

  1. Rendering to Images: Due to the canvas workaround, we lose the interactive text layer since content is rendered to static images prior to conversion. This only matters if users want to select and copy/paste from, or search text in their PDFs.

  2. Image Quality: Rendering content as image raster rather than precise, scalable vector makes documents or images blurry when viewed on large and high-def screens, when printed, or if containing large images or drawings.

  3. Rendering Accuracy: The html2pdf library relies on third-party technology. As a result, the community states it cannot help should you encounter rendering errors in your documents. As of writing, the html2canvas GitHub has 751 open issues.

Streamlining with Document Generation from Office Files

A fourth potetnial issue is also that of template creation; HTML is fine so long as you don't expect to create many templates or change them often. In contrast, a solution that supports doc gen from Office formats like docx, pptx, and xlsx enables users to control template creation without relying on dev resources.

For that reason, we now provide our customers a simple, professional doc gen method in WebViewer.

WebViewer has a built-in Office engine to generate PDFs from templates in Office formats, no servers, MS Office software, or MS Office licenses required. It drops into any web app directly and supports all modern frameworks including React, Angular, Vue, Blazor, etc. (We even offer a Salesforce-specific build as a Lightning Web Component!)

You can check out the web-based demo to try these doc gen features in your browser.

Wrap Up

Generating PDFs from HTML is no piece of cake. But following this guide, you can now generate simple documents, like invoices, right in your web app using pure JavaScript and make those PDFs downloadable by your users!

For more information on html2pdf.js, check out the community documentation. Please contact us with any questions, whether about this guide or our WebViewer doc gen solution.