How to Set Up html-to-pdfmake in the Browser: A Complete Guide

Load the PDFMake library, the virtual file system fonts, and the html-to-pdfmake browser bundle via CDN, then call the global htmlToPdfmake() function to convert HTML strings into PDFMake document definitions.

The html-to-pdfmake library, maintained by aymkdn, converts HTML fragments into JSON document definitions compatible with PDFMake. Unlike server-side solutions, this tool runs entirely in the browser, parsing HTML strings using the native DOMParser API and recursively transforming nodes into PDFMake-compatible objects.

What is html-to-pdfmake?

html-to-pdfmake is a framework-agnostic UMD module that bridges HTML and PDFMake. The core logic resides in index.js, which implements the htmlToPdfMake class for parsing and conversion. For browser environments, the library provides a UMD wrapper in browser.js that exposes a global htmlToPdfmake function on the window object, making it accessible without module loaders.

Browser Setup Methods

The simplest way to set up html-to-pdfmake is to include three scripts in your HTML: PDFMake core, the virtual file system fonts, and the browser bundle of html-to-pdfmake.

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>html-to-pdfmake Setup</title>
  <!-- PDFMake core + fonts -->
  <script src="https://cdn.jsdelivr.net/npm/pdfmake@latest/build/pdfmake.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/pdfmake@latest/build/vfs_fonts.min.js"></script>
  <!-- Browser build of html-to-pdfmake -->
  <script src="https://cdn.jsdelivr.net/npm/html-to-pdfmake@latest/browser.js"></script>
</head>
<body>
  <button id="gen">Generate PDF</button>
  
  <script>
    document.getElementById('gen').addEventListener('click', function () {
      const html = `<h2>Hello World</h2><p>This is a test.</p>`;
      const pdfDefinition = htmlToPdfmake(html);
      pdfMake.createPdf({ content: pdfDefinition }).download('test.pdf');
    });
  </script>
</body>
</html>

After loading these scripts, the global htmlToPdfmake function becomes available on the window object.

Method 2: ES Modules with Bundlers

If you use Webpack, Rollup, or Vite, you can import the library directly. The package.json defines a browser field pointing to the UMD build, allowing bundlers to resolve the browser-compatible version automatically.

import pdfMake from 'pdfmake/build/pdfmake.min.js';
import pdfFonts from 'pdfmake/build/vfs_fonts.js';
pdfMake.vfs = pdfFonts.pdfMake.vfs;

// Import html-to-pdfmake (bundler will use the browser field)
import htmlToPdfmake from 'html-to-pdfmake';

function generatePdf() {
  const htmlFragment = document.getElementById('content').innerHTML;
  
  const pdfDef = htmlToPdfmake(htmlFragment, {
    imagesByReference: true,
    tableAutoSize: true
  });
  
  pdfMake.createPdf({ content: pdfDef }).open();
}

Method 3: Local Browser Bundle

For offline development or custom builds, copy the pre-built browser bundle from the repository's docs/ directory. The file docs/browser-2.5.32.js (or the latest version) contains the minified UMD build ready for direct inclusion.

<script src="./local-js/pdfmake.min.js"></script>
<script src="./local-js/vfs_fonts.js"></script>
<script src="./local-js/html-to-pdfmake.browser.js"></script>

How the Browser Conversion Works

Understanding the internal mechanics helps debug complex conversions. The library follows a specific pipeline implemented across browser.js and index.js.

UMD Environment Detection

The browser.js file wraps the core logic in a Universal Module Definition (UMD) pattern that detects the execution environment:

(function (f) {
  if (typeof exports === "object" && typeof module !== "undefined") { 
    module.exports = f(); 
  }
  else if (typeof define === "function" && define.amd) { 
    define([], f); 
  }
  else { 
    window.htmlToPdfmake = f(); 
  }
})(function () { 
  // Core implementation from index.js
});

In a standard browser, the else branch executes, assigning the factory function to window.htmlToPdfmake.

Core Conversion Pipeline

When you call htmlToPdfmake(html, options), the library executes the following steps defined in index.js:

  1. Construction: The function creates an instance of the internal htmlToPdfMake class, storing configuration flags like tableAutoSize, imagesByReference, and a reference to the window object for DOM parsing.

  2. HTML Parsing: The convertHtml method instantiates a DOMParser using this.wndw.DOMParser() and parses the input string:

    var parser = new this.wndw.DOMParser();
    var parsedHtml = parser.parseFromString(htmlText, 'text/html');
  3. Recursive Traversal: The parseElement method walks the DOM tree depth-first. For each node, it:

    • Constructs PDFMake nodes ({text: ...}, {table: ...}, {image: ...})
    • Applies default styles from this.defaultStyles
    • Merges user-provided options including customTag handlers and ignoreStyles
    • Handles special elements like tables (with colspan/rowspan logic), lists, images (<img>), SVGs, and horizontal rules
  4. Style Resolution: The applyStyle method processes CSS by:

    • Concatenating ancestor classes (format: html-TAG) unless removeTagClasses is set
    • Parsing inline style attributes via parseStyle
    • Converting CSS units (px, em, pt) to PDFMake points using convertToUnit
    • Translating borders, backgrounds, fonts, line-height, and text-decoration to PDFMake schema
  5. Result Composition: The convertHtml method returns either a plain PDFMake node or, when imagesByReference is true, an object {content, images} where external URLs are stored under generated keys like img_ref_0.

The entire process executes client-side without server requests, leveraging the browser's native DOM capabilities.

Complete Working Example

Here is a production-ready implementation demonstrating the full integration, including error handling and advanced options:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>html-to-pdfmake Browser Setup</title>
  <script src="https://cdn.jsdelivr.net/npm/pdfmake@latest/build/pdfmake.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/pdfmake@latest/build/vfs_fonts.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/html-to-pdfmake@latest/browser.js"></script>
  <style>
    #content { border: 1px solid #ccc; padding: 20px; margin: 20px 0; }
  </style>
</head>
<body>
  <h1>PDF Generator</h1>
  
  <div id="content">
    <h2>Invoice #1234</h2>
    <p>Date: <strong>2024-01-15</strong></p>
    <table style="width: 100%;">
      <tr>
        <th>Item</th>
        <th>Qty</th>
        <th>Price</th>
      </tr>
      <tr>
        <td>Consulting</td>
        <td>5</td>
        <td>$100</td>
      </tr>
    </table>
    <p>Total: <strong>$500</strong></p>
  </div>

  <button id="download">Download PDF</button>
  <button id="open">Open PDF</button>

  <script>
    const contentDiv = document.getElementById('content');
    
    function getPdfDefinition() {
      const html = contentDiv.innerHTML;
      
      // Convert HTML to PDFMake definition
      const converted = htmlToPdfmake(html, {
        tableAutoSize: true,
        imagesByReference: false,
        defaultStyles: {
          h2: { fontSize: 18, bold: true, margin: [0, 10, 0, 5] },
          table: { margin: [0, 5, 0, 15] },
          th: { bold: true, fillColor: '#eeeeee' }
        }
      });
      
      return {
        content: converted,
        defaultStyle: {
          font: 'Roboto'
        }
      };
    }
    
    document.getElementById('download').addEventListener('click', () => {
      const docDefinition = getPdfDefinition();
      pdfMake.createPdf(docDefinition).download('document.pdf');
    });
    
    document.getElementById('open').addEventListener('click', () => {
      const docDefinition = getPdfDefinition();
      pdfMake.createPdf(docDefinition).open();
    });
  </script>
</body>
</html>

This example demonstrates the three-script setup pattern, the htmlToPdfmake global function, and common configuration options like tableAutoSize and defaultStyles.

Configuration Options

When calling htmlToPdfmake(html, options), you can pass an options object to control the conversion behavior. These options are processed in index.js during the construction phase:

  • tableAutoSize (boolean): Automatically calculates table column widths based on content rather than using fixed widths. This is handled in the case "TABLE": block within the recursive parser.

  • imagesByReference (boolean): When true, the function returns an object with content and images properties. External image URLs are stored under generated keys (e.g., img_ref_0) in the images object, allowing PDFMake to fetch them asynchronously. When false, images are embedded as base64 data URIs directly in the content.

  • defaultStyles (object): Overrides the built-in style mappings for HTML tags. The default styles are defined in this.defaultStyles within the constructor, mapping tags like h1, p, strong, and em to PDFMake style objects.

  • customTag (function): A callback that receives {element, node, parents} and returns a PDFMake node or null. This allows handling custom HTML tags or modifying standard conversion behavior.

  • ignoreStyles (array): A list of CSS properties (e.g., ['font-family', 'color']) to ignore during the style resolution phase in applyStyle.

  • removeTagClasses (boolean): When true, prevents the library from adding default classes like html-h1 or html-p to the PDFMake nodes.

  • window (object): Allows passing a custom window object (useful for testing or non-browser environments like jsdom).

Summary

Setting up html-to-pdfmake in the browser requires three steps:

  • Load dependencies: Include PDFMake core, virtual file system fonts, and the html-to-pdfmake browser bundle (available via CDN or local file).
  • Call the converter: Use the global htmlToPdfmake(htmlString, options) function to transform HTML into a PDFMake document definition.
  • Generate PDF: Pass the returned definition to pdfMake.createPdf() to download, open, or render the PDF.

The library operates entirely client-side, using the browser's native DOMParser (as implemented in index.js) to parse HTML and recursively convert elements into PDFMake-compatible JSON structures.

Frequently Asked Questions

Do I need a server to use html-to-pdfmake?

No. The library runs entirely in the browser using native JavaScript APIs. The convertHtml method in index.js instantiates a DOMParser from the browser's window object to parse HTML strings locally, and all style calculations and node transformations happen client-side without network requests.

Why must I load vfs_fonts.js before using the library?

PDFMake requires font data stored in a virtual file system to embed text in generated PDFs. The vfs_fonts.js file initializes pdfMake.vfs with base64-encoded font binaries. Without this, pdfMake.createPdf() will throw errors when attempting to render text nodes created by htmlToPdfmake.

Can I use html-to-pdfmake with modern frameworks like React or Vue?

Yes. While the CDN approach exposes a global htmlToPdfmake function, you can also import the library into bundled applications. The package.json specifies a browser field for bundler compatibility. Import the UMD build or the npm package, then call htmlToPdfmake within your component methods, passing the resulting definition to pdfMake.createPdf().

How do I handle external images when generating PDFs?

Set the imagesByReference option to true when calling htmlToPdfmake. This returns an object with content and images properties, where external URLs are stored under generated keys like img_ref_0. Pass this entire object to pdfMake.createPdf() so the library can fetch images asynchronously. If false, the parser attempts to embed images as base64 data URIs directly in the content array.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →