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:
- To generate the HTML out of PDF.
- 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();
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);
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);
})
}
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);
});
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 <font size=”3″ color=”red”>This is p one</font> 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);
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.
This, this and this were helpful.
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);
});
});
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]})
So, this is how a project is done, converting HTML to PDF using JavaScript.
And all I did was Google searches.
But how it all works? Want to know? Click here.
Some genuinely interesting points you have written. Assisted me a lot, just what I was looking for : D.