Download HTML as a PDF in React

Mohammad Faisal - Jun 11 '23 - - Dev Community

To read more articles like this, visit my blog

Downloading PDF is a common use-case in modern front-end applications. But building PDF on the client-side can be painful. In React we have some awesome libraries like react-pdf/renderer to help us.

Problems With the Traditional Libraries

react-pdf/renderer is an awesome library and provides lots of customization. but it comes with its own cost. For example

  • You have to design a separate component for your PDF document

  • Sometimes the rendering fails if you don’t handle edge-cases properly

  • You have to style separately and according to their specification.

All of these are okay if you want to build a data-heavy and customized PDF. But what if you want something simpler?

What if you just want to print the component that is being rendered as it is?

Let’s see how we can download any component as a PDF using a neat trick and some JavaScript knowledge.

Overview

The process that we are going to follow is converting the HTML element into an image and then putting the image into another powerful PDF library.

HTML document -> Image -> PDF

For this, we need two libraries.

  1. html2canvas -> will convert our HTML document to image

  2. jspdf -> will insert the generated image into a PDF file

The fullomplete code is at the bottom. If you are interested only in that go there directly. Otherwise bear with me. It won’t take long

Step 1. Install Dependencies

First, install the required dependencies.

yarn add jspdf html2canvas
Enter fullscreen mode Exit fullscreen mode

STEP 2: Add The Downloader Function

Now Either create a separate component for your GenericPdfdownloader or put the following code inside the component you want to download.

const downloadPdfDocument = (rootElementId) => {
  const input = document.getElementById(rootElementId);
  html2canvas(input)
    .then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
        const pdf = new jsPDF();
        pdf.addImage(imgData, 'JPEG', 0, 0);
        pdf.save("download.pdf");
    })
}
Enter fullscreen mode Exit fullscreen mode

What the code is doing

  • Input -> This function takes rootElementId as input. This will be the id of the downloadable component. We can define the id of any element like the following
return <div id="divToDownload">  

  // YOUR OTHER COMPONENT CODE GOES HERE

</div>
Enter fullscreen mode Exit fullscreen mode

So if we want to download the component inside the div with the id=”divToDownload” then we have to pass ”divToDownload” into the function

1. Getting the HTML Element

In the next step, we are getting the HTML element with the passed Id.

const input = document.getElementById(rootElementId);
Enter fullscreen mode Exit fullscreen mode

2. Converting HTML to Image

Next, we pass the element into the html2canvas which gives us back an image

html2canvas(input)
    .then((canvas) => {
        const imgData = canvas.toDataURL('image/png');
    })
Enter fullscreen mode Exit fullscreen mode

3. Putting The Image into PDF

Next, we create a new PDF document and put the image inside that.

const pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.save("download.pdf");
Enter fullscreen mode Exit fullscreen mode

Here the two zeroes are padding for the generated PDF document. You can change them as you want.

Also, you can modify the downloadable file name.

Complete code

Here is the full code for a custom PDF downloader which takes two arguments:

  1. The root elements id as rootElementId

  2. Download filename downloadFileName

import React from 'react';
import html2canvas from "html2canvas";
import { jsPDF } from "jspdf";

const GenericPdfDownloader = ({rootElementId , downloadFileName}) => {

    const downloadPdfDocument = () => {
        const input = document.getElementById(rootElementId);
        html2canvas(input)
            .then((canvas) => {
                const imgData = canvas.toDataURL('image/png');
                const pdf = new jsPDF();
                pdf.addImage(imgData, 'JPEG', 0, 0);
                pdf.save(`${downloadFileName}.pdf`);
            })
    }

    return <button onClick={downloadPdfDocument}>Download Pdf</button>

}

export default GenericPdfDownloader;
Enter fullscreen mode Exit fullscreen mode

Now you can just place this component anywhere in your project like the following:

import React from'react';
import GenericPdfDownloader from "./views/GenericPdfDownloader";

function App() {
  return (
    <>
        <GenericPdfDownloader 
          downloadFileName="CustomPdf" 
          rootElementId="testId" 
        />

        <div id="testId"> 
            This is A Downloadable Component 
        </div>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

export default App;

Conclusion

There you go! Now you have your custom PDF downloader that can be used anywhere in your project. Thank you for reading!

Have something to say?

Get in touch with me via LinkedIn or my Personal Website.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .