DEV Community

Cover image for Effortless PDF Generation in Vue
Majid Eltayeb
Majid Eltayeb

Posted on

Effortless PDF Generation in Vue

Note: This blog post was originally published on my personal blog Majid's

Have you ever wondered if you can download an HTML table as a PDF file? Recently, while working on a side project using Nuxt3, I ran into this same question. I needed to generate a table of data and make it shareable with others. I found many libraries that can do this, but none of them had a good example in Vue. So, I thought it might be useful to share my method with others.

To download an HTML table as a PDF file, we need to use two libraries:

dom-to-image: This library allows capturing a screenshot of a DOM element and returning a data URI containing a PNG image.

jsPDF: This library allows creating a PDF document in JavaScript.

Let's get started with the steps:

Step 1: Install the Libraries

npm install jspdf -S
npm install dom-to-image -S
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a PDF Document Now, we need to create a PDF document using the jsPDF constructor. Here's the code:

// new jsPDF(orientation, unit, dimensions, ...otherOptions) 
const pdf = new jsPDF('l', 'pt', [tableWidth, tableHeight]);
Enter fullscreen mode Exit fullscreen mode

as you can see, this constructor takes some options, we will use 3 of them

  • l: The orientation of the PDF document. l stands for landscape and p stands for portrait. In this case, l is used to create a landscape-oriented PDF.
  • pt: The unit of measurement used to specify the dimensions of the PDF document. pt stands for points, which is a common unit of measurement for printed materials.
  • [tableWidth, tableHeight]: An array specifying the width and height of the PDF document in points. These values are based on the size of the HTML table being converted to a PDF.

Step 3: Add the HTML as an Image

  • We need to add the HTML table as an image to our PDF document using the addImage method. Here's the code:
// addImage(imageData, format, x, y, width, height, alias, compression, rotation)
pdf.addImage(imageData, 'PNG', 0, 0, tableWidth, tableHeight);
Enter fullscreen mode Exit fullscreen mode
  • imageData: the data of the image to be inserted (we don't have this image yet!)
  • PNG: the format of the image to be inserted.
  • 0, 0: the X and Y coordinates of the image's top-left corner in the PDF document.
  • tableWidth, tableHeight: the width and height of the image to be inserted in the PDF document.

but since we don't have imageData yet, and here is where we're going to use dom-to-image library

Step 4: Capture the HTML Table as an Image

domtoimage.toPng(HTMLElement);
Enter fullscreen mode Exit fullscreen mode

domtoimage.toPng is a method provided by the dom-to-image library which allows capturing a screenshot of a DOM element and returning a data URI containing a PNG image. The method takes the DOM element as an argument and returns a Promise that resolves with the data URI.

Step 5: Save the PDF File

pdf.save("table.pdf");
Enter fullscreen mode Exit fullscreen mode

Here is a full vue example

<template>
  <div class="wrapper">
    <table ref="table">
      <thead>
        <tr>
          <th>Month</th>
          <th>Revenue</th>
          <th>Profit</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>January</td>
          <td>$10,000</td>
          <td>$2,000</td>
        </tr>
        <tr>
          <td>February</td>
          <td>$15,000</td>
          <td>$3,000</td>
        </tr>
        <tr>
          <td>March</td>
          <td>$12,000</td>
          <td>$2,500</td>
        </tr>
        <tr>
          <td>April</td>
          <td>$20,000</td>
          <td>$5,000</td>
        </tr>
      </tbody>
    </table>

    <button @click="onDownload">Download PDF</button>
  </div>
</template>
<script setup>
import { ref } from "vue";
import { jsPDF } from "jspdf";
import domtoimage from "dom-to-image";

const table = ref(null);

const onDownload = () => {
  const tableWidth = table.value.clientWidth;
  const tableHeight = table.value.clientHeight;

  // Convert HTML table to PNG image using dom-to-image
  domtoimage.toPng(table.value).then((imageData) => {
    // Create a new jsPDF document
    const pdf = new jsPDF("l", "pt", [tableWidth, tableHeight]);
    // Add the PNG image to the PDF document
    pdf.addImage(imageData, "PNG", 0, 0, tableWidth, tableHeight);
    // Save the PDF document
    pdf.save("table.pdf");
  });
};
</script>
Enter fullscreen mode Exit fullscreen mode

Check the Codesandbox

Final notes

Creating PDF documents from HTML tables in Vue.js can be a powerful way to allow users to share data in a portable and professional format. In this example, we used the jsPDF library to generate a PDF document and the dom-to-image library to convert an HTML table to a PNG image that was added to the PDF. However, keep in mind that if you're using a custom font in your table, you may need to add the font to the PDF as well. Be sure to check the jsPDF documentation for further guidance on adding custom fonts to your PDF documents. Happy coding! 🧑🏻‍💻

Top comments (3)

Collapse
 
noudadrichem profile image
Noud Adrichem

How would you approach having multiple pages that have the same footer/header?
Looks like the current setup does not really include any default print sizes like A4 and multi page support.

Collapse
 
ringeringeraja profile image
ringeringeraja

This has nothing to do with Vue.

Collapse
 
majidzeno profile image
Majid Eltayeb • Edited

Thanks to the composition api for making it sounds like that 😅, but yes, it is not a much of a Vue , just a ref to catch the element and the onDownload method 👍