DEV Community

Cover image for HTML to PDF JavaScript – Example with Code
Awan Shrestha
Awan Shrestha

Posted on

HTML to PDF JavaScript – Example with Code

In this blog we will see how we can convert the HTML site to PDF using JavaScript.

For a project, I needed to convert some HTML to PDF using JavaScript.

It was a basic site. There would be a form inside a div, and all I needed to do was generate the pdf out of that div and show it in a new tab. All in the client side, no backed server.

The main tasks here were:

  1. To generate the HTML out of PDF.
  2. To show the generated pdf in a new tab.

HTML to PDF using JavaScript

So, the first part here. Pretty simple HTML to PDF.

A quick Google Search and I came upon this html2pdf library.

As stated in its documentation “html2pdf.js converts any webpage or element into a printable PDF entirely client-side using html2canvas and jsPDF.”

That was all I wanted. There were lots of other tutorials out there on it as well.

It all worked and it downloaded the pdf as well. But the pdf was blank.

html2pdf generate and return Blank or Empty PDF

That was a bit of weird. A few searches and turns out, there were some issues with the version.

Used the 0.9.3 version and issue solved.

CDN Link: https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js

It printed the div with all the contents.

JavaScript Code:

let element = document.getElementById('div-to-print')

html2pdf().from(element).save();
Enter fullscreen mode Exit fullscreen mode

So, it saved / downloaded the pdf file.

But I didn’t need it to be downloaded, I need it to show in a new browser tab.

Open PDF in new tab instead of Download – JavaScript – using Blob

We need to create a new blob from the pdf file and create new URL to show that file. Reading this issue, I got to know that using html2pdf promise API, we could get the file instead of downloading it. And then use it to create the blob.

How we would do it with a normal file.

const filed = document.querySelector('input[type=file]').files[0];
let file = new Blob([filed], { type: 'application/pdf' });
let fileURL = URL.createObjectURL(file);
window.open(fileURL);
Enter fullscreen mode Exit fullscreen mode

Using it with the pdf generated from HTML by html2pdf:


async function printHTML() {

let worker = await html2pdf().from(element).toPdf().output('blob').then((data) => {
    console.log(data)
    let fileURL = URL.createObjectURL(data);
    window.open(fileURL);
    })
}
Enter fullscreen mode Exit fullscreen mode

It worked. The PDF was now not downloading, but being opened in new tab. And now, I styled the div using CSS. But there was problem.

html2pdf CSS Not Working

The CSS I had written for the div was not loading up. The CSS was not working with html2pdf.

A few searches, and found out that external CSS was not being loaded up by html2css. So, only HTML was being printed. Not the CSS.

The workaround was to write CSS in HTML with style tag or to use inline CSS. Also, few workarounds in this issue.

Finally the PDF was being generated as I needed. Just one more caveat.

html2pdf PDF Text not Selectable

The texts in PDF were not being selectable. Now this might not be an requirement for most of the projects, but I needed it.

html2pdf generates pdf as canvas image. It had been using html2canvas all along. So, there were no texts. They were just canvas images out of HTML being converted to PDF.

I had to search for another library. Why not use the one I had been using all the way along under the hood.

jsPDf is used by html2pdf. So, I tried for jsPDF.


doc.fromHTML(document.getElementById("div-to-print"),
     22, // Margins
     17,
     {'width': 400},
     function (a) {
          // doc.save("HTML2PDF.pdf"); // To Save
          let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });
          let blobUrl = URL.createObjectURL(blobPDF);
          window.open(blobUrl);
});
Enter fullscreen mode Exit fullscreen mode

And all good here.

Open PDF in new tab instead of downloading from jsPDF

As for opening in new tab instead of downloading PDF from jsPDF, similar as in html2pdf case, in the callback function, we can pass doc.output() to create the blob.

And the PDF being generated was in text, not images.

So, all good and I added the CSS. But.

jsPDF CSS not Working

Turns out jsPDF does not work with CSS. And to make it work with CSS, it was to use html2canvas. And that’s what html2pdf had been doing all along.

We can easily pass margins in the jsPDf. And also it supported the html attributes as This is p one as old times. But the reason I was needing CSS was because the div I was trying to print had two divs inside of it. And one of them needed to be centered aligned both vertically and horizontally.

The next thing I was searching was “How to center align div child with HTML only without using CSS”.

Turns out there was text API in the jsPDF that would take multiple parameters and make the job easy without CSS.

API.text = function(text, x, y, flags, angle, align);
Enter fullscreen mode Exit fullscreen mode

Multiple such texts and the job would be done.

But instead of writing multiple texts, if I could do it with multiple HTML elements with withHTML function, then that could be great. Turns out it works.

By adding another HTML element block in callback of function adding previous block, it could be done.

A few more calculations, and using the calculated values as margins, it could be perfectly center aligned.


let pageHeight = doc.internal.pageSize.height || doc.internal.pageSize.getHeight()
let pageWidth = doc.internal.pageSize.width || doc.internal.pageSize.getWidth()
let recipientBlock = document.querySelector(".div2-block")
let rHeight = recipientBlock.clientHeight
let rWidth = recipientBlock.clientWidth

doc.fromHTML(document.querySelector(".div1-block"),
   22, 17, { 'width': 200, 'height': 200 },
   function (a) {
      doc.fromHTML(document.querySelector(".div2-block"),
          pageWidth / 2 - rWidth / 4,
          pageHeight / 2 - rHeight / 4,
          { 'width': 200, 'height': 200 },
          function (a) {
              let blobPDF = new Blob([doc.output()], { type: 'application/pdf' });
              let blobUrl = URL.createObjectURL(blobPDF);
              window.open(blobUrl);
                });
        });
Enter fullscreen mode Exit fullscreen mode

Finally, around the end of the project.

Finally, one more thing was to do. That was to set the width and height of the final pdf.

It was given there in documentation and pretty easy.

Pass the Height and Width as an array and specify the unit. For some reasons, unit: “px” for pixels was having problems. So, used the “pt”. It worked.

let doc =new jsPDF({orientation: 'l', unit: 'pt', format: [widthForJsPDF, heightForJsPDF]})
Enter fullscreen mode Exit fullscreen mode

So, this is how a project is done, converting HTML to PDF using JavaScript.

And all I did was Google searches.

Top comments (11)

Collapse
 
thomasbnt profile image
Thomas Bnt

Hello ! Don't hesitate to put colors on your codeblock like this example for have to have a better understanding of your code 😎

console.log('Hello world!');
Enter fullscreen mode Exit fullscreen mode

Example of how to add colors and syntax in codeblocks

Collapse
 
aayyusshh_69 profile image
Aayush Pokharel

Good advice.

Collapse
 
gyftunez profile image
Stephen Uchenna

I remember trying to send a resumee I took all day writing the code and applying css to the html but external... Printed it but got all plain color only... I nearly ran mad, because my employer was waiting to get it as soon as possible... I had it submitted like that with it dividing each section horizontally 😂😂...

Collapse
 
mahmud-r-farhan profile image
Mahmudur Rahman

Great post! 🚀 If you want to explore another approach, check out this GitHub repository. It converts images to PDFs efficiently and might offer some useful insights for similar projects. I would love to hear your thoughts on it!

Collapse
 
agarshan profile image
agarshan

Yeah on that we cant select the text if it converts images to pdfs

Collapse
 
perisicnikola37 profile image
Nikola Perišić

Nice post! If you want to see parsing HTML using React.js and TypeScript, take a look of this GitHub repository.
It's custom logic parsing HTML content and already has 14 stars.

Collapse
 
agarshan profile image
agarshan

What happens if you want to break the content to multiple pages? Did u try?
And also try with some images, if images exceed the page the images will break.
Just wanted information you on these limitations
You have to fix them for yourself

Collapse
 
cc_f9f91ece754f4e626078c2 profile image
cc44599 • Edited

nice!

Collapse
 
fstrube profile image
Franklin Strube

Is this just creating an image in a PDF? That's not great for PDF accessibility (yes, it's a thing, just like accessibility on the web).

Collapse
 
asjadansari07 profile image
Asjed Ansari • Edited

Is it possible to download pdf without rendering html or without using an Iframe?

Collapse
 
skyhayato profile image
SKY-HaYaTo

Wow! Nice code! Thank you!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.