Generate pdf from HTML in div using Javascript

All I want to do is to print to pdf whatever is found in the div with an id of "pdf". This must be done using JavaScript. The "pdf" document should then be automatically downloaded with a filename of "foobar.pdf" I've been using jspdf to do this, but the only function it has is "text" which accepts only string values. I want to submit HTML to jspdf, not text.

29k 16 16 gold badges 92 92 silver badges 138 138 bronze badges asked Aug 12, 2013 at 16:18 John Crawford John Crawford 9,985 10 10 gold badges 32 32 silver badges 43 43 bronze badges

As mentioned above I do not want to use the "text" function. I want to give it HTML. Your link only deals with plain text and not html

Commented Aug 12, 2013 at 16:26 jsPDF does have a fromHTML function; see the "HTML Renderer" example at: mrrio.github.io/jsPDF Commented May 6, 2014 at 21:51

19 Answers 19

jsPDF is able to use plugins. In order to enable it to print HTML, you have to include certain plugins and therefore have to do the following:

  1. Go to https://github.com/MrRio/jsPDF and download the latest Version.
  2. Include the following Scripts in your project:

If you want to ignore certain elements, you have to mark them with an ID, which you can then ignore in a special element handler of jsPDF. Therefore your HTML should look like this:

    

print this to pdf

Then you use the following JavaScript code to open the created PDF in a PopUp:

var doc = new jsPDF(); var elementHandler = < '#ignorePDF': function (element, renderer) < return true; >>; var source = window.document.getElementsByTagName("body")[0]; doc.fromHTML( source, 15, 15, < 'width': 180,'elementHandlers': elementHandler >); doc.output("dataurlnewwindow"); 

For me this created a nice and tidy PDF that only included the line 'print this to pdf'.

Please note that the special element handlers only deal with IDs in the current version, which is also stated in a GitHub Issue. It states:

Because the matching is done against every element in the node tree, my desire was to make it as fast as possible. In that case, it meant "Only element IDs are matched" The element IDs are still done in jQuery style "#id", but it does not mean that all jQuery selectors are supported.

Therefore replacing '#ignorePDF' with class selectors like '.ignorePDF' did not work for me. Instead you will have to add the same handler for each and every element, which you want to ignore like:

var elementHandler = < '#ignoreElement': function (element, renderer) < return true; >, '#anotherIdToBeIgnored': function (element, renderer) < return true; >>; 

From the examples it is also stated that it is possible to select tags like 'a' or 'li'. That might be a little bit to unrestrictive for the most usecases though:

We support special element handlers. Register them with jQuery-style ID selector for either ID or node name. ("#iAmID", "div", "span" etc.) There is no support for any other type of selectors (class, of compound) at this time.

One very important thing to add is that you lose all your style information (CSS). Luckily jsPDF is able to nicely format h1, h2, h3 etc., which was enough for my purposes. Additionally it will only print text within text nodes, which means that it will not print the values of textareas and the like. Example:

25.1k 16 16 gold badges 94 94 silver badges 111 111 bronze badges answered Jul 18, 2014 at 12:32 5,077 2 2 gold badges 29 29 silver badges 36 36 bronze badges

I'm going to guess the element handler can be a class? That would be much more semantically in line with HTML5 standards. An ID not only carries too much speificity weight in CSS, it also has to be unique.

Commented Jan 3, 2015 at 7:28 @snrlx I get blank pdf and this error: renderer.pdf.sHashCode is not a function Commented Mar 23, 2016 at 3:39

"If you want to ignore certain elements, you have to mark them with an ID" - a wonderful library, ruined by that inverted reqiurement. The OP wanted to print a single

, which could be one of hundreds - so he has to mark all the unwanted DOM elements??

Commented Jan 24, 2017 at 19:13 If I'm not wrong doc.fromHTML is no longer supported Commented Feb 14, 2021 at 18:56 doc.fromHTML() has been deprecated and replaced with doc.html() Commented Nov 7, 2022 at 3:02

This is the simple solution. This works for me. You can use the javascript print concept and simple save this as pdf.

      
8,080 18 18 gold badges 75 75 silver badges 123 123 bronze badges answered Nov 24, 2015 at 10:04 vaibhav kulkarni vaibhav kulkarni 1,791 15 15 silver badges 21 21 bronze badges "and simple save this as pdf" - I missed that part. How do you do it? Commented Jan 24, 2017 at 19:16

This worked for me, for solving the problem of CSS styling, I created another css file called printPDF.css and added using link tag just like this in above example: printWindow.document.write('DIV Contents'); printWindow.document.write(''); printWindow.document.write('');

Commented Feb 16, 2017 at 6:43

Some comments: 1) You don't need an especific stylesheet for printing. In your current stylesheet, do something like: @media print < .pageBreak < page-break-before: always; >.labelPdf < font-weight: bold; font-size: 20px; >.noPrintPdf < display: none; >> and use these classes as your needs. 2) .live("click", . ) doesn't work to me, so I use .on("click", . ) instead.

Commented Sep 13, 2017 at 14:19

@DavidsonLima this code creates new window which will not see old window css. That's why it's "ignoring" css, it's not ignoring, just in new window it's not loaded. Just load it in head and it will be rendering.

Commented May 6, 2018 at 13:40

Just in case any one is trying to make this happen with Angular, please put your CSS file in the assets folder.

Commented Mar 14, 2019 at 16:34

This served me for years now:

export default function printDiv() < let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150'); mywindow.document.write(`$ `); mywindow.document.write(''); mywindow.document.write(document.getElementById(divId).innerHTML); mywindow.document.write(''); mywindow.document.close(); // necessary for IE >= 10 mywindow.focus(); // necessary for IE >= 10*/ mywindow.print(); mywindow.close(); return true; > 

Of course this will open print dialog and user will have to know she/he can select print to pdf option, to get pdf. There may be printer pre-selected and if user confirms may get this document actually printed. To avoid such situation and to provide PDF without any extras, you need to make PDF file. Probably on the server side. You could have tiny html page with invoice only and convert it to PDF file with headless chrome. It's super easy with puppeteer. No need to install/config chrome, just install npm package puppeteer (managed by chrome team) and run it. Keep in mind this will actually launch real chrome just w/o GUI, so you need to have some RAM & CPU for this. Most servers will be fine with low enough traffic. Here is code sample but this must run on the BACKEND. Nodejs. Also it's slow call, it's resources intensive call. You should run it NOT on api call but e.g. after invoice was created - create pdf for it and store, if pdf was not generated yet, just show message to try again in couple minutes.

const puppeteer = require('puppeteer'); (async () => < const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://your-domain.com/path-to-invoice', < waitUntil: 'networkidle2', >); await page.pdf(< path: 'invoice-file-path.pdf', format: 'a4' >); await browser.close(); >)();