94

I'm trying to print a specific part of my application.

The application has a list of users, displaying their first and last name. When I click a user I get a popup with more detailed information about them.

How would I go about printing just the popup for a user I clicked? The popup looks like this:

 <div id="user<?=$user->id;?>" class="popup">
      <div class="details">
           User details...
      </div>
      <a href="#print">Print</a>
 </div>

The print button isn't working yet though.

Gregor Menih
  • 5,036
  • 14
  • 44
  • 66
  • 3
    possible duplicate of [Print
    only?](http://stackoverflow.com/questions/468881/print-div-id-printarea-div-only)
    – Brad Werth Sep 19 '14 at 22:18

19 Answers19

187

You can use simple JavaScript to print a specific div from a page.

var prtContent = document.getElementById("your div id");
var WinPrint = window.open('', '', 'left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0');
WinPrint.document.write(prtContent.innerHTML);
WinPrint.document.close();
WinPrint.focus();
WinPrint.print();
WinPrint.close();
Mystical
  • 2,505
  • 2
  • 24
  • 43
pmtamal
  • 2,157
  • 1
  • 12
  • 7
  • 41
    Be careful if the div that you're printing with this code requires any CSS to render they way you want. If it does you'll have to make sure you add it to the page as well using `WinPrint.document.write(cssLinkTag)`. – Wally Lawless Jan 11 '14 at 04:57
  • What if I want to change the orientation? – Si8 Feb 12 '14 at 19:32
  • This does not work to print a div when the div contains data obtained from the server side:http://stackoverflow.com/questions/34206638/print-a-div-with-data-from-ajax-or-jquery-get – Core_Dumped Dec 11 '15 at 12:58
  • 9
    A fiddle based on this answer: https://jsfiddle.net/jdavidzapatab/6sctvg2z/ – David Aug 05 '17 at 17:40
  • 1
    @WallyLawless could you provide an example of how you might derive the css tag? – karns May 29 '20 at 20:30
  • If you want all the neccessary css easily, instead of calling to '' (empty), you can create a file only with a head and all the css links, wait for the load, and replace the innerHTML of the body, with your content – Federico G Dec 22 '20 at 18:03
  • you don't need window to print, iframe is enough. Also not use document.write() – zb' Jan 27 '21 at 03:27
  • 1
    How to specify the cssLinkTag: `WinPrint.document.write('');` – Genki Dec 16 '22 at 19:50
16

You would have to open a new window(or navigate to a new page) containing just the information you wish the user to be able to print

Javscript:

function printInfo(ele) {
    var openWindow = window.open("", "title", "attributes");
    openWindow.document.write(ele.previousSibling.innerHTML);
    openWindow.document.close();
    openWindow.focus();
    openWindow.print();
    openWindow.close();
}

HTML:

<div id="....">
    <div>
        content to print
    </div><a href="#" onclick="printInfo(this)">Print</a>
</div>

A few notes here: the anchor must NOT have whitespace between it and the div containing the content to print

SReject
  • 3,774
  • 1
  • 25
  • 41
  • This is brilliant! Of course if you don't want the print link after your item, or you'd like it to be a bit prettier, you have some challenges. I solved that challenge by giving the href an ID, changing Print to non breaking space, and referencing the click() event elsewhere with getElementById. Thank you!! – Mmm Aug 23 '15 at 01:16
  • ah finally after trying a trillion html-to-pdf solutions from angular/typescript, a simple one that works – hocikto Dec 07 '21 at 18:38
16

I made this jQuery extension to print the HTML of the element selected: $('#div2').print();

$.fn.extend({
    print: function() {
        var frameName = 'printIframe';
        var doc = window.frames[frameName];
        if (!doc) {
            $('<iframe>').hide().attr('name', frameName).appendTo(document.body);
            doc = window.frames[frameName];
        }
        doc.document.body.innerHTML = this.html();
        doc.window.print();
        return this;
    }
});

See it in action here.

fresskoma
  • 25,481
  • 10
  • 85
  • 128
  • Doesn't work for me with Chrome. Also you should try to post your code here in the answer. – Mike Oct 13 '16 at 14:32
  • 10
    I think that, instead of wildly downvoting someone who's posted an easy salvageable answer, we as a community may in fact try to _not_ scare them off by commenting and just copying the damn code over ourselves v_v Don't expect everyone to be so familar with the intricacies of StackOverflow etiquette... – fresskoma Oct 13 '16 at 16:30
  • Thanks but why css files cant be added? – Hamid Reza Aug 07 '17 at 07:24
13

Instead of all the complicated JavaScript, you can actually achieve this with simple CSS: just use two CSS files, one for your normal screen display, and another for the display of ONLY the content you wish to print. In this latter file, hide everything you don't want printed, display only the pop up.

Remember to define the media attribute of both CSS files:

<link rel="stylesheet" href="screen-css.css" media="all" />
<link rel="stylesheet" href="print-css.css" media="print" />
Cedric Ipkiss
  • 5,662
  • 2
  • 43
  • 72
  • 1
    I make the complicated JavaScript because I have more that 1 button to select the area to print. I use the css "@media print {" to hide the buttons. – Alessandro Lettieri Oct 23 '18 at 09:04
8

Just use CSS to hide the content you do not want printed. When the user selects print - the page will look to the " media="print" CSS for instructions about the layout of the page.

The media="print" CSS has instructions to hide the content that we do not want printed.

<!-- CSS for the things we want to print (print view) -->
<style type="text/css" media="print">

#SCREEN_VIEW_CONTAINER{
        display: none;
    }
.other_print_layout{
        background-color:#FFF;
    }
</style>

<!-- CSS for the things we DO NOT want to print (web view) -->
<style type="text/css" media="screen">

   #PRINT_VIEW{
      display: none;
   }
.other_web_layout{
        background-color:#E0E0E0;
    }
</style>

<div id="SCREEN_VIEW_CONTAINER">
     the stuff I DO NOT want printed is here and will be hidden - 
     and not printed when the user selects print.
</div>

<div id="PRINT_VIEW">
     the stuff I DO want printed is here.
</div>
5

Styles

 @media print {

       .no-print{
               display : none !important;
                }
              }

Jquery

    function printInvoice()
 {
     printDiv = "#printDiv"; // id of the div you want to print
     $("*").addClass("no-print");
     $(printDiv+" *").removeClass("no-print");
     $(printDiv).removeClass("no-print");

     parent =  $(printDiv).parent();
     while($(parent).length)
     {
         $(parent).removeClass("no-print");
         parent =  $(parent).parent();
     }
     window.print();

 }

Print Button Html

<input type="button" onclick="printInvoice();" value="Print">
zainul ogna
  • 160
  • 2
  • 4
3

Here is my enhanced version that when we want to load css files or there are image references in the part to print.

In these cases, we have to wait until the css files or the images are fully loaded before calling the print() function. Therefor, we'd better to move the print() and close() function calls into the html. Following is the code example:

var prtContent = document.getElementById("order-to-print");
var WinPrint = window.open('', '', 'left=0,top=0,width=384,height=900,toolbar=0,scrollbars=0,status=0');
WinPrint.document.write('<html><head>');
WinPrint.document.write('<link rel="stylesheet" href="assets/css/print/normalize.css">');
WinPrint.document.write('<link rel="stylesheet" href="assets/css/print/receipt.css">');
WinPrint.document.write('</head><body onload="print();close();">');
WinPrint.document.write(prtContent.innerHTML);
WinPrint.document.write('</body></html>');
WinPrint.document.close();
WinPrint.focus();
hailong
  • 1,409
  • 16
  • 19
2

Try this:

  1. Dump the innerHTML of the container into the iFrame (plus any print-specific CSS
  2. print the iFrame contents.

Try it out in JSFiddle (iframes don't appear to work in StackOverflow's preview)

You can see the code here, but it won't work due to what are probably security limitations in StackOverflow's renderer.

const printButton = document.getElementById('print-button');

printButton.addEventListener('click', event => {
  // build the new HTML page
  const content = document.getElementById('name-card').innerHTML;
  const printHtml = `<html>
      <head>
          <meta charset="utf-8">
          <title>Name Card</title>
      </head>
      <body>${content}</body>
  </html>`;
      
  // get the iframe
  let iFrame = document.getElementById('print-iframe');
  
  // set the iFrame contents and print
  iFrame.contentDocument.body.innerHTML = printHtml;
  iFrame.focus();
    iFrame.contentWindow.print();
  
});
<h1>Print your name badge</h1>
<div id="name-card" class="card">
  <p>Hello my name is</p>
  <h2>Max Powers</h2>
</div>
<p>You will be required to wear your name badge at all times</p>
<a id="print-button" class="btn btn-primary">Print</a>

<iframe id="print-iframe" width="0" height="0"></iframe>
Adonis Gaitatzis
  • 3,189
  • 26
  • 24
2

You can use this JQuery plugin

aphoe
  • 2,586
  • 1
  • 27
  • 31
1

I Got a better option,

First separate the printable and nonprintable section by class name or id

window.onafterprint = onAfterPrint;

function print(){
  //hide the nonPrintable div  
}

function onAfterPrint(){
  // Visible the nonPrintable div
}
<input type="button" onclick="print()" value="Print"/>

That's all

Arul
  • 1,031
  • 13
  • 23
  • I wouldn't say better, and you should definetely share a tiny example. But this looks like a really nice way of doing it. There could be a `.printable` class for instance. However, this would mess with the CSS (fixed positions for instance). – Ulysse BN Jan 17 '19 at 13:47
1

try this one.

export function printSectionOfWebpage(sectionSelector) {
    const $body = jquery('body');
    const $sectionToPrint = jquery(sectionSelector);
    const $sectionToPrintParent = $sectionToPrint.parent();
    const $printContainer = jquery('<div style="position:relative;">');

    $printContainer.height($sectionToPrint.height()).append($sectionToPrint).prependTo($body);

    const $content = $body.children().not($printContainer).not('script').detach();

    /**
     * Needed for those who use Bootstrap 3.x, because some of
     * its `@media print` styles ain't play nicely when printing.
     */
    const $patchedStyle = jquery('<style media="print">')
        .text(
            `
          img { max-width: none !important; }
          a[href]:after { content: ""; }
        `
        )
        .appendTo('head');

    window.print();

    $body.prepend($content);
    $sectionToPrintParent.prepend($sectionToPrint);

    $printContainer.remove();
    $patchedStyle.remove();
}
skchawala
  • 11
  • 4
0

As answered here: https://stackoverflow.com/a/1072151/421243, you can add the specific section to a hidden frame with Javascript, focus it, and print it.

Community
  • 1
  • 1
David Cook
  • 483
  • 7
  • 25
0

I wrote a tiny JavaScript module called PrintElements for dynamically printing parts of a webpage.

It works by iterating through selected node elements, and for each node, it traverses up the DOM tree until the BODY element. At each level, including the initial one (which is the to-be-printed node’s level), it attaches a marker class (pe-preserve-print) to the current node. Then attaches another marker class (pe-no-print) to all siblings of the current node, but only if there is no pe-preserve-print class on them. As a third act, it also attaches another class to preserved ancestor elements pe-preserve-ancestor.

A dead-simple supplementary print-only css will hide and show respective elements. Some benefits of this approach is that all styles are preserved, it does not open a new window, there is no need to move around a lot of DOM elements, and generally it is non-invasive with your original document.

See the demo, or read the related article for further details.

András Szepesházi
  • 6,483
  • 5
  • 45
  • 59
0

Here what worked for me

With jQuery and https://developer.mozilla.org/en-US/docs/Web/API/Window/open

  var $linkToOpenPrintDialog = $('#tvcPrintThisLinkId');
  var windowObjectReference = null;
  var windowFeatures = 'left=0,top=0,width=800,height=900,menubar=no,toolbar=no,location=yes,resizable=no,scrollbars=no,status=no';
  var windowFeaturesStyles = '<link rel="stylesheet" media="print" href="/wp-content/themes/salient-child/dist/css/app-print.css">';

  $linkToOpenPrintDialog.on('click', function(event) {
    openPrintDialog(this.href, this.target, 'tvcInnerCalculatorDivId', event);    
    return false;
  });

  function openPrintDialog(url, windowName, elementToOpen, event) {

    var elementContent = document.getElementById(elementToOpen);

    if(windowObjectReference == null || windowObjectReference.closed) {

      windowObjectReference = window.open( url, windowName, windowFeatures);
      windowObjectReference.document.write(windowFeaturesStyles);
      windowObjectReference.document.write(elementContent.innerHTML);
      windowObjectReference.document.close();
      windowObjectReference.focus();
      windowObjectReference.print();
      windowObjectReference.close();

    } else {
      windowObjectReference.focus();
    };

    event.preventDefault();
  }

app-print.css

@media print { 

  body { 
    margin: 0; 
    color: black; 
    background-color: white;
  } 

}
atazmin
  • 4,757
  • 1
  • 32
  • 23
0

If there are a lot of css dependencies, the solutions above become difficult to use. If you

  • don't mind using a 3rd party library (html2canvas)
  • don't mind that all @media print css rules will be ignored (can be worked around)

you can try a slightly modified approach of @pmtamal 's answer.

  • Convert the html content in the target div to canvas
  • Open a new window and attach the canvas to that window
  • Print

Code Example:

let prtContent = document.querySelector(target);

html2canvas(prtContent).then(canvas => {
   let WinPrint = window.open('', '', 'left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0');
   WinPrint.document.body.appendChild(canvas);
   WinPrint.document.close();
   WinPrint.focus();
   WinPrint.print();
   WinPrint.close();

});

Vivek Kodira
  • 2,764
  • 4
  • 31
  • 49
0

This answer covers printing one "specific part" of multiple "specific parts" on page.

Steps:

  1. Place your "specific part" in a section (some kind of container). Each section should have a button with a value matching the ID of the section.
  2. Style the section as needed you want in to appear on print. (basiclly it's how it appears in the browser window).
  3. Create @media print rules.
  4. Create javascript js function.

Example:

html:

<container>
<button type="button" onclick="print(this.value)" value="1">Print</button>
<section id="1">
...."specific part" that will be printed
</section>
</container>

<container>
<button type="button" onclick="print(this.value)" value="2">Print</button>
<section id="2">
...."specific part" that will be printed
</section>
</container>

<container>
<button type="button" onclick="print(this.value)" value="3">Print</button>
<section id="3">
...."specific part" that will be printed
</section>
</container>

<container>
<button type="button" onclick="print(this.value)" value="4">Print</button>
<section id="4">
...."specific part" that will be printed
</section>
</container>

css: // note here #PrintThis can be whatever ID you want.

@media print {
  body * {
    visibility: hidden;
  }
  #printThis, #printThis * {
    visibility: visible;
  }
  #printThis {
    position: absolute;
    left: 0;
    top: 0;
  }
}

js:

function print(sectionID) {
// get the ID of the section to be printed
    let section = document.getElementById(sectionID)
// set the ID of the section to match CSS @media print rules
    section.setAttribute("id", "printThis")
// print the section
    window.print();
// set back the ID of the section to what it was...
    section.setAttribute("id", sectionID)
}
0
<style type="text/css">
@media print {
    body {
        visibility:hidden;
    }
    body * {
        display:none;
    }
    body *:has(.print_this), body .print_this, body .print_this * {
        display:block;
    }
    body .print_this {
        visibility:visible;
    }
}
</style>
    
    <h1>nope</h1>
    <div>
        <h2>nope</h2>
        <div class="print_this">
            <h3>yep</h3>
            yep
        </div>
        nope *
        <h4>nope</h4>
    </div>
    <h2>nope</h2>

* At first I only used display:none/block but I found that if print_this (or its parents) had a untagged text node sibling, they would appear in the print. So I had to add the visibility:hidden/visible to handle that.

-1

In printPageArea() function, pass the specific div ID which you want to print. I've found this JavaScript code from codexworld.com.

function printPageArea(areaID){
    var printContent = document.getElementById(areaID);
    var WinPrint = window.open('', '', 'width=900,height=650');
    WinPrint.document.write(printContent.innerHTML);
    WinPrint.document.close();
    WinPrint.focus();
    WinPrint.print();
    WinPrint.close();
}

The complete code and tutorial can be found from here - How to Print Page Area using JavaScript.

JoyGuru
  • 1,803
  • 20
  • 11
-1

Try this awesome ink-html library

import print from 'ink-html'
// const print = require('ink-html').default

// js
print(window.querySelector('#printable'))
// Vue.js
print(this.$refs.printable.$el)