How to Print Using an iframe with JavaSrcipt (without wahala)

Ayomikun OsotaAyomikun Osota
4 min read

Have you ever clicked a button and, like magic, a document or receipt starts printing? That was exactly what I needed my users to feel when I first tried to implement a print feature. But building it wasn’t magic—it took me a whole day. If you’ve Googled “how to print a div in JavaScript” (hopefully this article pops up for you now, haha), you’ll find a simple print function that either opens the div in a new window and prints it, or one that slaps the div into your current document’s body and print it. These methods seemed quick fixes, but they caused me problems like:

  • User experience: Opening a new window can be intrusive and confusing for users. Additionally, temporarily replacing the body content with the content you want to print and then setting it back creates a noticeable “dancing or jumpy content” on the screen.

  • Pop-up blockers: Some browsers might have pop-up blocking enabled which may block new windows or tabs from opening thereby cause the print function to fail silently.

  • Performance issues: Re-rendering the entire document, especially for large or complex web pages, can be resource-intensive. This can slow down the browser, causing a laggy experience for the user.

I just knew there had to be a better way. After a bit of brainstorming with my very smart AI friend Chatty (that’s right, I’m not alone here!), I stumbled on the perfect solution: iframes.

Why iframes?

Seriously, it all started making sense because you can basically pop a mini document into an iframe and print that without breaking your whole page. This means no flickering, no pop-ups and better control over what gets printed.

Step 1: Prepare your HTML and CSS

Before diving into iframes, make sure your HTML and CSS are ready to go. This might seem straight forward for you this senior dev reading this but trust me it’s not. You might not be able to easily use frameworks like Tailwind because your existing styles and settings won’t be available (ugh). Additionally, you want to find a way to add the css in both you main website and your print content while avoiding css bleeding and style inconsistencies.

Step 2: Printing

Let’s say you have this awesome receipt you want to print. You’ll start by creating a hidden iframe and appending it to your document. The beauty of using an iframe is that it can easily be hidden from view, unlike a new browser window.

Once the iframe is tucked away out of sight, you append it to the body, then you write a brand-new document inside the iframe. This includes the stuff you want to print. And, instead of closing the iframe after printing (which can cause its own issues), you used the afterprint event to remove the iframe and do some post-print magic.

const print = () => {

  const printContents = document.getElementById("printable").innerHTML;

  // Create a hidden iframe
  const iframe = document.createElement("iframe");
  iframe.srcdoc = "<!DOCTYPE html>";
  iframe.style.position = "absolute";
  iframe.style.left = "-9999px"; // Hide the iframe

  // Append the iframe to the body
  document.body.appendChild(iframe);

  // Write the content to the iframe's document
  var doc = iframe.contentWindow?.document;
  doc?.open();
  doc?.write(`
  <!DOCTYPE html>
        <html class="print-frame">
          <head>
          <link rel="stylesheet" href="/src/assets/style/printable.css">
          <title> </title>
          </head>
          <body class="printarea">
            ${printContents}
          </body>
        </html>
      `);
  doc?.close();

  const printWindow = iframe.contentWindow;

  if (printWindow) {
    // Set focus on the iframe and trigger print
    printWindow.focus();
    printWindow.print();

    // Add an event listener for afterprint to clean up and send the estimate
    printWindow.addEventListener("afterprint", () => {
      // Clean up the iframe after printing
      document.body.removeChild(iframe);

      // Call any other function after printing
      sendInvoice();
    });
  }
};

Handling Printing Issues

So, like any good developer (or bad one, depending on your perspective), I hit a few snags along the way.

  • Background colors weren’t printing correctly: Yeah, apparently, printers don’t like background colors for some reason. But this was an easy fix with a little CSS tweak.

  • Removing default headers and footers: The above CSS also helps by removing any unnecessary page margins that might sneak in when printing.

The fix is simple—add the following styles inside a media query:

@media print {
    @page {
        margin: 0; // Removes default headers and footers
    }

    .print-frame body {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact; // Adds missing background color
    }
}

Step 3: Add a Keyboard Shortcut

For a smooth user experience, I added a shortcut to trigger printing when users press Ctrl + P (or Cmd + P on Mac).

function addKeyboardShortcut() {
    const handleKeydown = (event: KeyboardEvent) => {
        if (
            (event.ctrlKey || event.metaKey) &&
            event.key === 'p'
        ) {
            event.preventDefault();
            print();
        }
    };

    window.addEventListener('keydown', handleKeydown);

    return () => {
        window.removeEventListener('keydown', handleKeydown);
    };
}

Now, if you know a better way, let’s start a conversation in the comments—I’d love to hear your ideas and what’s worked for you! 😄

0
Subscribe to my newsletter

Read articles from Ayomikun Osota directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayomikun Osota
Ayomikun Osota