How to convert HTML(CSS) To PDF Using JavaScript

Github avatar
April 28, 2015.5 min read

JavaScript was a language used for basic things like form validations. Now the javascript can do so many things which were only possible by server-side technologies such as PHP and With New HTML5 API’s Canvas, SVG, video, audio and etc… we can do things lot easier now than before. Ok now, why am I telling all this now? Because in this tutorial we going to see how to convert an HTML page to a pdf document using JavaScript.

Update: v2 avaible at //

Demo download

To do it I’m going to use and We will html2canvas to take a screenshot (It will parse the DOM, Calculate the styles applied). Html2canvas returns the canvas object. Once we have the canvas object we will use it to create an image using the build in toDataURL() function. toDataURL() function will return a base64 encoded image as string. Finally, we will use the jsPDF to create PDF document. Enough explanation lets dive into the actual code now. First, of let’s create HTML from which we want to generate our pdf document. For better understanding, I would like to create HTML form with not less than 10 controls in it. To create UI we will use semantic UI.


<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>HTML to PDF - techumber </title> <link rel="stylesheet" type="text/css" href="//" /> </head> <body> <div class="ui page grid"> <div class="wide column"> <h1 class="ui header aligned center">HTML to PDF </h1> <div class="ui divider hidden"> </div> </div> </div> <!-- scripts --> <script src="//"> </script> <script type="text/javascript" src="//"> </script> <script type="text/javascript" src="//"> </script> <script type="text/javascript" src="app.js"> </script> </body> </html> ript> </body> </html>

Added semantic UI cdn link for our styles. html2canvas and jsPdf added thought rawgit cdn.


<div class="ui segment"> <div class="ui button aligned center teal" id="create_pdf">Create PDF</div> <div class="ui divider"></div> <form class="ui form"> <h4 class="ui dividing header">Personal Information</h4> <div class="two fields"> <div class="field"> <label for="">First Name </label> <input type="text" name="first-name" placeholder="First Name" /> </div> <div class="field"> <label for="">Last Name </label> <input type="text" name="last-name" placeholder="First Name" /> </div> </div> <div class="field"> <label>Biography </label> <textarea> </textarea> </div> <h4 class="ui dividing header">Account Info</h4> <div class="two fields"> <div class="required field"> <label>Username </label> <div class="ui icon input"> <input type="text" placeholder="Username" /> <i class="user icon"> </i> </div> </div> <div class="required field"> <label>Password </label> <div class="ui icon input"> <input type="password" /> <i class="lock icon"> </i> </div> </div> </div> <h4 class="ui top attached header">Import Settings</h4> <div class="ui bottom attached segment"> <div class="grouped fields"> <label for="alone">Would you like us to import your current settings? </label> <div class="field"> <div class="ui checkbox"> <input type="radio" checked="" name="import" /> <label>Yes </label> </div> </div> <div class="field"> <div class="ui checkbox"> <input type="radio" name="import" /> <label>No </label> </div> </div> </div> </div> <h4 class="ui dividing header">Settings</h4> <h5 class="ui header">Privacy</h5> <div class="field"> <div class="ui checkbox"> <input type="radio" name="privacy" /> <label>Allow <b>anyone </b> to see my account </label> </div> </div> <div class="field"> <div class="ui checkbox"> <input type="radio" name="privacy" /> <label>Allow <b>only friends </b> to see my account </label> </div> </div> <h5 class="ui header">Newsletter Subscriptions</h5> <div class="field"> <div class="ui checkbox"> <input type="checkbox" name="top-posts" /> <label>Top Posts This Week </label> </div> </div> <div class="field"> <div class="ui checkbox"> <input type="checkbox" name="hot-deals" /> <label>Hot Deals </label> </div> </div> <div class="ui hidden divider"></div> <div class="field"> <div class="ui checkbox"> <input type="checkbox" name="hot-deals" /> <label>I agree to the <a href="#">Terms of Service </a>. </label> </div> </div> <div class="ui error message"> <div class="header">We noticed some issues</div> </div> <div class="ui submit button blue">Register</div> </form> </div>

I created a simple HTML form using semantic UI.


(function() { var form = $('.form'), cache_width = form.width(), a4 = [595.28, 841.89]; // for a4 size paper width and height $('#create_pdf').on('click', function() { $('body').scrollTop(0); createPDF(); }); //create pdf function createPDF() { getCanvas().then(function(canvas) { var img = canvas.toDataURL('image/png'), doc = new jsPDF({ unit: 'px', format: 'a4', }); doc.addImage(img, 'JPEG', 20, 20);'techumber-html-to-pdf.pdf'); form.width(cache_width); }); } // create canvas object function getCanvas() { form.width(a4[0] * 1.33333 - 80).css('max-width', 'none'); return html2canvas(form, { imageTimeout: 2000, removeContainer: true, }); } })();

Now, this is important. The app.js will contain main JavaScript code that we going to use for our app to work. getCanvas function will return promised object later we can use it in other places. In creating PDF we converting the canvas to image and adding that image to jsPDF function addImage.

Here, you need to have few tricks. First jsPDF support many document formats. Since a4 is most popular we will use the same there. We are changing the form width to a4 size default width so that we can get exact screenshot otherwise the image will overflow when we add it to PDF document.

We always have to make sure to our page scroll in top position otherwise, we won't get extract screenshot. To do so we are having $('body').scrollTop(0) function.