Effortless PDF Generation in Vue
Tags: vue, pdf, html, htmltopd
Published: 2023-04-04 21:50:31

_Note: This blog post was originally published on my personal blog [Majid's](https://blog.majidz.com/effortless-pdf-generation-in-vue)_


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
```

**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]);
```

as you can see, this constructor takes [some options](https://artskydj.github.io/jsPDF/docs/jsPDF.html), 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);
```

- `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);
```

`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");
```

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>
```

Check the [Codesandbox](https://codesandbox.io/p/sandbox/sharp-jerry-5sx89c?file=%2Fpackage.json&selection=%5B%7B%22endColumn%22%3A21%2C%22endLineNumber%22%3A12%2C%22startColumn%22%3A21%2C%22startLineNumber%22%3A12%7D%5D)

## 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](https://artskydj.github.io/jsPDF/docs/jsPDF.html) for further guidance on adding custom fonts to your PDF documents. Happy coding! 🧑🏻‍💻