Convert HTML to PDF with JavaScript: Top libraries compared

Table of contents

    Do you need to generate a PDF from HTML in your JavaScript app? You’ve got options, but not all of them are built the same. This guide compares three top JavaScript tools: html2pdf, pdfmake, and Playwright. It also explains how each one handles HTML-to-PDF conversion, their pros and cons, and which library is best suited for client-side, structured, or high-fidelity PDF generation.
    Convert HTML to PDF with JavaScript: Top libraries compared
    TL;DR:

    If you want to convert HTML to PDF in a JavaScript-based app, you can choose between open source libraries and full-featured services like Nutrient. Use html2pdf.js for simple, client-side exports. For structured documents with selectable text, pdfmake gives you full control in JavaScript. For pixel-perfect, CSS-accurate output, Playwright is the best, though it requires a server.

    But if you’re looking for a faster and more scalable solution, Nutrient offers platform-specific SDKs, a robust PDF generation API, and no-code integrations, all designed to handle HTML-to-PDF conversion with greater fidelity, automation, and deployment flexibility.

    Do you need to generate a PDF from HTML in your JavaScript app? You’ve got a lot of options, and some of the most robust ones come from Nutrient.

    From frontend libraries to enterprise-scale services, Nutrient provides HTML-to-PDF solutions for every platform:

    Convert HTML to PDF seamlessly with Nutrient SDK

    Learn how to generate PDFs directly from HTML using JavaScript — with full control over layout, styles, and interactive features.

    Once you’ve explored Nutrient’s full-stack options, this guide compares three open source tools — html2pdf.js(opens in a new tab), pdfmake(opens in a new tab), and Playwright(opens in a new tab) — to help you choose the right approach for your app.

    So, how do these tools actually work in practice? This post will begin with the simplest option: html2pdf.js.

    1. html2pdf.js — Simple client-side PDF generation

    The html2pdf(opens in a new tab) library converts HTML pages to PDFs in the browser. It uses html2canvas(opens in a new tab) and jsPDF(opens in a new tab) under the hood. html2canvas renders an HTML page into a canvas element and turns it into a static image. jsPDF then takes the image and converts it to a PDF file.

    Check out our blog on how to convert HTML to PDF using React for a step-by-step guide on how to use jsPDF in a React app.

    Installation methods (CDN, npm, and manual download)

    You can add html2pdf.js in three ways:

    • Using the CDN link for html2pdf

    The library provides a CDN link. If you prefer this method, add a script tag to your HTML file:

    Terminal window
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js" integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzZ8zBps+dvLusV+eNQATqgA/HdeKFVgA5v3S/cIrLF7QnIg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    • Installing via npm
    Terminal window
    npm install html2pdf.js
    • Downloading the library manually

    Get the bundle from GitHub(opens in a new tab). After you’ve downloaded the library, add a script tag to your HTML file:

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

    Convert HTML to PDF using html2pdf

    To begin, define a generatePDF() function that will get the element you want to download as a PDF from your HTML files. Then, call html2pdf with that element to download it directly on your users’ client. Next, call the following function in a download button:

    <!DOCTYPE html>
    <html>
    10 collapsed lines
    <head>
    <!-- html2pdf CDN link -->
    <script
    src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"
    integrity="sha512-GsLlZN/3F2ErC5ifS5QtgpiJtWd43JWSuIgh7mbzZ8zBps+dvLusV+eNQATqgA/HdeKFVgA5v3S/cIrLF7QnIg=="
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
    ></script>
    </head>
    <body>
    <button id="download-button">Download as PDF</button>
    <div id="invoice">
    <h1>Our Invoice</h1>
    </div>
    <script>
    const button = document.getElementById("download-button");
    function generatePDF() {
    // Choose the element that your content will be rendered to.
    const element = document.getElementById("invoice");
    // Choose the element and save the PDF for your user.
    html2pdf().from(element).save();
    }
    button.addEventListener("click", generatePDF);
    </script>
    </body>
    </html>

    In the example above, you only rendered the h1 title. However, you can render any HTML element, including images and tables. In the next example, you’ll use a more complex HTML structure.

    To test this example locally, run a quick static server with:

    Terminal window
    npx serve -l 4111 .

    Then open http://localhost:4111(opens in a new tab) in your browser to interact with the PDF download button.

    html2pdf example

    Advanced example: Downloading an invoice as a PDF

    You can download an invoice template as a PDF by clicking this link. You can also generate the HTML for your own invoice on your backend if you prefer.

    Similar to the example above, you’ll use the generatePDF() function to download the invoice as a PDF. However, this time, you’ll render the invoice template to the div element.

    The end result will look like what’s shown below.

    Preview of a fully rendered HTML invoice

    2. pdfmake — Build PDFs from structured data

    The pdfmake(opens in a new tab) library generates PDF documents directly in the browser. It uses a layout and style configuration defined in a JSON-like structure within JavaScript, leveraging pdfkit(opens in a new tab) under the hood for PDF generation.

    Unlike html2pdf.js, which converts rendered HTML into a static image before converting it to a PDF, pdfmake explicitly defines the document structure in JavaScript, allowing for greater customization and text selection capabilities. This makes pdfmake ideal for situations where selectable text is necessary.

    Installation

    Add via CDN:

    Terminal window
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.72/pdfmake.min.js" integrity="sha384-qwfyMhpwB4dOhtxItT9bxl/sd7WQ95MvXSyLUgVz3oNRlvK/Ea7uT4O3rf1ZriyH" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.72/vfs_fonts.js" integrity="sha384-vD7JPR0c5DJMoqHXO7lJKsK9k6XPlL4LMoGK1jHsGBWoDzW9BGfaP7UWKIXHdz7L" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    Or, install via npm:

    Terminal window
    npm install pdfmake

    Generate PDFs from HTML using pdfmake

    Define a generatePDF() function with your PDF content as a JavaScript object. Then use pdfmake to create and download the file. You can trigger it with a button in your HTML. While the example uses simple text and a table, pdfmake also supports lists, images, and advanced styling for more complex layouts.

    <!DOCTYPE html>
    <html>
    12 collapsed lines
    <head>
    <script
    src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.72/pdfmake.min.js"
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
    ></script>
    <script
    src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.72/vfs_fonts.js"
    crossorigin="anonymous"
    referrerpolicy="no-referrer"
    ></script>
    </head>
    <body>
    <button onclick="generatePDF()">Download Invoice</button>
    <!-- Move script here so pdfMake is loaded -->
    <script>
    function generatePDF() {
    const docDefinition = {
    content: [
    { text: "Invoice", style: "header" },
    {
    table: {
    body: [
    ["Item", "Qty", "Price"],
    3 collapsed lines
    ["Product 1", "2", "$10"],
    ["Product 2", "1", "$20"],
    ["Total", "", "$40"],
    ],
    },
    },
    ],
    styles: {
    header: { fontSize: 18, bold: true },
    },
    };
    pdfMake.createPdf(docDefinition).download("invoice.pdf");
    }
    </script>
    </body>
    </html>

    You can test the example by running:

    Terminal window
    npx serve -l 4111 .

    pdfmake example

    Benefits of using pdfmake

    • Selectable text — Unlike html2pdf.js, pdfmake preserves text as selectable and copyable.
    • Custom styling — Define font sizes, colors, and positioning with structured JavaScript.
    • Advanced layouts — Supports tables, lists, and multi-column designs.

    3. Playwright — Server-side HTML-to-PDF rendering

    Playwright(opens in a new tab) is a framework that provides an API to control headless Chrome, Firefox, and WebKit browsers with a single API, allowing you to convert webpages into PDFs. This enables you to automate nearly all tasks that can be done manually in a browser, including generating PDFs from web content. The difference between Playwright and html2pdf is that you need to run Playwright on your server and serve the PDF to your users.

    Installation

    Create a new project and install Playwright(opens in a new tab):

    Terminal window
    mkdir playwright-pdf-generation && cd playwright-pdf-generation
    npm init --yes
    npm install playwright

    Before using Playwright, make sure the required browser binaries are installed by running:

    Terminal window
    npx playwright install

    Basic PDF example

    You’ll now create an index.js file where you’ll require Playwright, launch a new browser session, go to your invoice page, and save the PDF file:

    index.js
    // Require Playwright.
    const { chromium } = require("playwright");
    (async function () {
    try {
    // Launch a new browser session.
    const browser = await chromium.launch();
    // Open a new page.
    const page = await browser.newPage();
    // Set the page content.
    await page.setContent("<h1>Our Invoice</h1>");
    // Generate a PDF and store it in a file named `invoice.pdf`.
    await page.pdf({ path: "invoice.pdf", format: "A4" });
    await browser.close();
    } catch (e) {
    console.error(e);
    }
    })();

    Running node index.js will generate invoice.pdf in your directory. But to let users download the PDF by clicking a button, set up a simple Node server using the http module.

    The server listens on /generate-pdf, uses Playwright to render the page, and streams the PDF directly to the browser. When users click a download button linked to this endpoint, they’ll receive the PDF instantly.

    To do this, omit the path option in page.pdf() to get a buffer, set the response header to application/pdf, and send the buffer as the response. For all other routes, return a simple HTML page with a link to trigger the PDF download.

    index.js
    const { chromium } = require("playwright");
    const http = require("http");
    // Create an instance of the HTTP server to handle the request.
    http
    .createServer(async (req, res) => {
    if (req.url === "/generate-pdf") {
    // Making sure to handle a specific endpoint.
    const browser = await chromium.launch();
    const page = await browser.newPage();
    // Set the content directly or navigate to an existing page.
    await page.setContent(`
    <!DOCTYPE html>
    <html>
    <head>
    <title>Invoice</title>
    </head>
    <body>
    <h1>Our Invoice</h1>
    <p>Details about the invoice...</p>
    </body>
    </html>
    `);
    // By removing the `path` option, you'll receive a `Buffer` from `page.pdf`.
    const buffer = await page.pdf({ format: "A4" });
    await browser.close();
    // Set the content type so the browser knows how to handle the response.
    res.writeHead(200, { "Content-Type": "application/pdf" });
    res.end(buffer);
    } else {
    // Respond with a simple instruction page.
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end(
    "<h1>Welcome</h1><p>To generate a PDF, go to [/generate-pdf](/generate-pdf).</p>",
    );
    }
    })
    .listen(3000, () => {
    console.log("Server is running on http://localhost:3000");
    });

    Open localhost:3000 in your browser, and you’ll see the instruction page. You can then navigate to /generate-pdf to open the PDF with the invoice.

    playwright example

    Ready to get started?

    Thousands of companies, organizations, governments, and developers use Nutrient’s software to enable collaboration, signing, markup, and more in their apps.

    Specific capabilities of each library

    Each library brings its own strengths to HTML-to-PDF conversion:

    • html2pdf.js — Converts HTML/CSS into image-based PDFs in the browser. Best for simple, static layouts like receipts or certificates. May struggle with layout fidelity and resolution.
    • pdfmake — Builds PDFs from JavaScript objects. Ideal for structured documents like invoices or reports. Offers high customization, selectable text, and table support.
    • Playwright — Renders full HTML/CSS in a headless browser and outputs a pixel-perfect PDF. Great for complex layouts and server-side automation.

    Performance overview

    • html2pdf.js — Lightweight and fast for small files, but browser memory limits can affect large documents.
    • pdfmake — Also client-side. Offers more flexibility but may slow down with complex content.
    • Playwright — Server-side rendering offloads work from the client. Suitable for large documents and consistent output at scale.

    Common issues and troubleshooting

    html2pdf.js

    • Blurry output — Use high-resolution images and scale properly.
    • CSS support — Limited styling; avoid modern layout features like flexbox or grid.
    • Large file sizes — Optimize HTML and images.

    pdfmake

    • Layout complexity — Manual configuration required; break documents into smaller blocks when needed.
    • Font issues — Ensure custom fonts are embedded correctly.

    Playwright

    • Requires a server — Setup is more involved than client-side tools.
    • Slower for large pages — Minimize dynamic scripts or unnecessary content before rendering.

    Feature comparison

    Featurehtml2pdf.jspdfmakePlaywright
    Ease of useVery easyModerateModerate
    InstallationSimple (CDN, npm)Simple (CDN, npm)npm
    Runs in browserCheckCheckCross
    Text selectionCrossCheckCheck
    CSS/HTML supportLimitedNoneFull
    CustomizationLowHighHigh
    PDF qualityMedium (image-based)High (structured content)Very high (browser rendering)
    PerformanceFast for small docsGood with structured layoutsHigh for large/complex layouts
    Use caseSimple exports, receiptsInvoices, reports, formsHigh-fidelity PDFs, automation
    ProsNo backend needed, easy setupSelectable text, layout controlPixel-perfect output, full CSS
    ConsBlurry output, no selectionManual config, no HTML inputServer setup, heavier runtime

    Which one should you use?

    • For simple client-side exports, use html2pdf.js. It’s quick and works without a backend.
    • For structured, data-driven documents, pdfmake is ideal thanks to its flexibility and text support.
    • For high-fidelity, CSS-accurate rendering, go with Playwright, especially if you already run a Node.js backend.
    Need more than basic HTML-to-PDF conversion?

    Upgrade to Nutrient’s SDK for advanced PDF generation with annotations, form filling, and customizable output — all in pure JavaScript.

    Conclusion

    If you’re working on a small project or need a quick way to generate PDFs in the browser, html2pdf.js is a convenient tool — it’s simple to use and runs entirely client-side. For more structured content, such as invoices or reports where selectable text is important, pdfmake provides full programmatic control through JavaScript. And when high-fidelity rendering of complex layouts is essential — including full CSS and media queries — Playwright delivers excellent results via server-side browser automation.

    However, these open source tools often require compromises. Client-side options may struggle with layout accuracy, font rendering, or large file sizes. Server-based tools like Playwright are powerful, but they require ongoing maintenance, browser dependencies, and custom logic to handle use cases like form field generation or document composition.

    That’s where Nutrient comes in — offering a modern, production-ready approach to HTML-to-PDF conversion that’s easy to integrate and scales with your needs:

    • For advanced layouts and forms, Document Engine renders HTML into pixel-perfect PDFs while supporting HTML form inputs, fillable fields, headers/footers, and more. It also enables chained operations — such as adding a cover page, applying a watermark, or merging PDFs — through a single API request.
    • For backend teams, the PDF generation API integrates seamlessly with Node.js, Python, Java, and other backend stacks. It’s a tech-agnostic HTTP API designed for server-side environments, where secure API key authentication is the standard.
    • For .NET developers, Nutrient .NET SDK lets you convert both local HTML files and live web content into PDFs using Chrome-based rendering, with full control from within your C# applications.
    • For mobile apps, the Android and iOS SDKs provide native APIs to generate PDFs directly on-device from HTML or URLs — ideal for generating invoices, tickets, or offline reports in mobile workflows.
    • For business and automation teams, Nutrient supports Zapier and Power Automate, making it easy to generate PDFs from HTML email templates, form submissions, or dynamic content — without writing any code.

    By using Nutrient, you can skip the piecemeal setup and avoid PDF generation issues tied to browser inconsistencies, rendering mismatches, and scaling limitations. Instead, you get consistent, secure, and high-fidelity results across every device, framework, and team.

    Whether you’re building a web app, automating reports, or embedding PDF generation in enterprise software, Nutrient offers the reliability and flexibility you need.

    Start your free trial now and turn your HTML into high-quality PDFs the easy way.

    Furthermore, we’re working on integrating PDF-to-HTML conversion functionality into Document Engine and DWS API, which will be available soon. Stay tuned for updates!

    FAQ

    Is there a faster way to generate PDFs without writing all the logic myself?

    Yes. If you want a ready-to-use solution that handles more than just HTML-to-PDF conversion, check out PDF generation with Document Engine. It supports features like converting HTML forms into fillable PDFs, chaining document operations (e.g. watermarking or merging), and exposing everything via an HTTP API with flexible auth. It’s ideal if you want to skip low-level PDF logic and focus on building your app.

    Does Nutrient support mobile platforms like iOS and Android?

    Yes. Nutrient offers native SDKs for both Android and iOS, enabling HTML-to-PDF conversion directly on mobile devices. These SDKs support rendering from strings or URLs, and they leverage WebKit (on iOS) or embedded rendering engines for high-fidelity output.

    Can I use the Nutrient PDF generation API in a frontend app?

    Yes, but for frontend apps, you should use JWT-based authorization rather than raw API keys. This provides secure, restricted access — for example, when using the API via Nutrient Web SDK in the browser. For server-side apps, API keys are the standard method.

    Does Nutrient support converting HTML forms into interactive fillable PDF forms?

    Yes. Nutrient Document Engine supports full conversion of HTML form elements into fillable PDF fields, including text inputs, checkboxes, and dropdowns — a feature not currently possible with Playwright or most open source libraries.

    How does Nutrient .NET SDK handle HTML-to-PDF conversion?

    The .NET SDK enables you to convert local HTML files or URLs to PDF using C#. It supports high-quality rendering via Chrome and includes support for both file-based and in-memory generation. This is ideal for desktop apps or backend services in .NET environments.

    Do Nutrient tools support high-fidelity rendering with full CSS support?

    Yes. Both Document Engine and the .NET SDK support accurate CSS rendering, including stylesheets, layout precision, and embedded media. These are suitable for complex use cases like branded reports, web templates, or responsive HTML layouts.

    Nicolas Dular

    Nicolas Dular

    Hulya Masharipov

    Hulya Masharipov

    Technical Writer

    Hulya is a frontend web developer and technical writer at Nutrient who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

    Mahmoud Elsayad

    Mahmoud Elsayad

    Web Engineer

    Explore related topics

    FREE TRIAL Ready to get started?