html2pdf.js render and export without flash


This post shows how to render HTML for html2pdf.js and export it as a PDF without causing a visible flash of content.

Problem

Sometimes you need to clone and render the content before passing it to html2pdf.js, for example when preparing a print-friendly version.

<div id="content">My content...</div>
const original = document.getElementById('content');
const clone = original.cloneNode(true);

clone.style.position = 'fixed';
clone.style.left = '-9999px';
clone.style.top = '0';
clone.style.width = `${original.offsetWidth}px`;

document.body.appendChild(clone);

html2pdf()
  .set({
    filename: 'document.pdf',
  })
  .from(clone)
  .save()
  .then(() => {
    clone.remove();
  });

However, rendering the clone offscreen can produce blank PDFs because html2canvas won’t capture it correctly. Rendering it in the viewport avoids that problem, but causes a visible flash of content.

Solution

The trick is to set z-index: -1:

 const original = document.getElementById('content');
 const clone = original.cloneNode(true);

 clone.style.position = 'fixed';
-clone.style.left = '-9999px';
+clone.style.left = '0';
 clone.style.top = '0';
+clone.style.zIndex = '-1';
 clone.style.width = `${original.offsetWidth}px`;

 document.body.appendChild(clone);

 html2pdf()
   .set({
     filename: 'document.pdf',
   })
   .from(clone)
   .save()
   .then(() => {
     clone.remove();
   });

This works because the clone remains inside the viewport, allowing html2canvas to capture it correctly. Setting z-index: -1 places it behind the rest of the page, so users never see it.

Tip

To exclude an element from the exported PDF, add the data-pdf-exclude="true" attribute:

<div data-pdf-exclude="true">Don't export me</div>


Please support this site and join our Discord!