How to print only a selected HTML element?
Asked Answered
A

20

45

I am trying to implement a print feature in HTML. I know I can print the whole page with window.print(), but how do I print only a specific page element? For example a particular <DIV>Some text to print</DIV>.

Azotobacter answered 28/6, 2011 at 2:33 Comment(2)
The same question has been asked before: #469381Stoneware
Possible duplicate of Print <div id="printarea"></div> only?Perpetual
G
47

You could use a print specific CSS stylesheet and hide everything but what you want printed.

<div class="no-print">I won't print</div><div class="something-else">I will!</div>

Just the no-print class will be hidden, but anything with a print class will show.

<style type="text/css" media="print">
   .no-print { display: none; }
</style>
Graham answered 28/6, 2011 at 2:34 Comment(11)
Hi manyxcxi, Any small example of doing this the CSS way? This <DIV> is a nested <DIV> many layers down.Azotobacter
The syntax for this is as follows: <link rel="stylesheet" type="text/css" media="print" href="print.css" /> - this tells the browser that when it send the page to the print spool, it should use that CSS instead.Fatherly
Superstringcheese, thanks for explaining. But this solution entails that I have to add 'class="no-print"' to 10's of <DIV>'s on my page. Correct?Azotobacter
Give the DIV an ID and refer to that in your print stylesheet. Set: body * {display:none;} and then #myDiv {display:normal;} (override the style only on that div). What you're doing is setting everything to invisible by default, then specifying the individual overrides you want.Fatherly
O ok.. got it. Will try to work on it.. in case I get stuck somewhere.. will post backAzotobacter
@Superstringcheese display: normal doesn't exist. I wish there was a generic option to turn on elementsCathey
@Cathey 'normal' meaning a normal option for that context: block, inline, etc. Sorry for the confusion. Probably most elements will be block. It's not elegant, but it will work. I normally take the approach of hiding what I don't want.Fatherly
@Graham is this still the valid way to implement print styles? also like such <link rel="stylesheet" media="mediatype and|not|only (expressions)" href="print.css">?Gastroenterostomy
@Gastroenterostomy That was an example of an inline style that's for print only. If you had an entire print only stylesheet you would want to do exactly as you've described using the media attribute on the stylesheet link.Graham
@Graham like, media="print" i knowGastroenterostomy
This is not an accepted answer for me because the element in want to print is inside an other element. The other contents of that element i don't want to printAlbuminuria
D
13

If you are familiar to jQuery, you can use jQuery Print Element plugin like this:

$('SelectorToPrint').printElement();
Disgruntle answered 28/6, 2011 at 4:7 Comment(4)
Is there a vanilla rendition of this?Reversioner
This does not work out of the box with newer jquery versions because it uses the "jQuery.browser" property that was removed. jQuery Doc says: This property was removed in jQuery 1.9 and is available only through the jQuery.migrate plugin. Please try to use feature detection instead.Dezhnev
i love jquery, all you need is search a plugin.Tick
@Tick this is exactly the reason why I don't like jQuery, you don't use your own logic to solve a problem, and once jQuery breaks or a plugin is out of date, you just don't know how to fix a certain situation. Better learn the depth of your browser if you want to be autonomous.Foretooth
O
11

Created something generic to use on any HTML element

HTMLElement.prototype.printMe = printMe;
function printMe(query){
  var myframe = document.createElement('IFRAME');
  myframe.domain = document.domain;
  myframe.style.position = "absolute";
  myframe.style.top = "-10000px";
  document.body.appendChild(myframe);
  myframe.contentDocument.write(this.innerHTML) ;
  setTimeout(function(){
  myframe.focus();
  myframe.contentWindow.print();
  myframe.parentNode.removeChild(myframe) ;// remove frame
  },3000); // wait for images to load inside iframe
  window.focus();
 }

Usage:

document.getElementById('xyz').printMe();
document.getElementsByClassName('xyz')[0].printMe();

Hope this help
Regards
Gaurav Khurana

Oligarch answered 2/4, 2016 at 11:25 Comment(1)
This ignore styles sheets styles.Woll
R
7

I found a solution that doesn't have the problems other solutions have. It copies the printed element to the body, and is fairly elegant and general:

CSS:

@media print {
  body *:not(.printable, .printable *) {
    // hide everything but printable elements and their children
    display: none;
  }
}

JS:

function printElement(e) {
  let cloned = e.cloneNode(true);
  document.body.appendChild(cloned);
  cloned.classList.add("printable");
  window.print();
  document.body.removeChild(cloned);
}

The only limitation is that the element loses styles it inherited from its previous parents. But it works on arbitrary elements in the document structure

Respiratory answered 10/12, 2021 at 12:23 Comment(1)
This seems far superior to a lot of the other solutions - it's fast, efficient, and maintains styling from the global scope of the page. As you say, the only limitation is that you can't rely on cascading styling rules from whatever elements the printable area was contained within, but that's a minor thing, and most of the other solutions don't support this either.Boling
C
5

Simple html and pure javascript works best. Parameter "this" refers to current id, so that function is universal for all ids. By using "ref.textContent" instead of "ref.innerHTML" you can extract only textual content for printing.

html body:

<div id="monitor" onclick="idElementPrint(this)">element to print
<img src="example.jpg" width="200">
</div>

pure javascript:

/*or:
monitor.textContent = "click me to print content";

const imga = new Image(200); //width
imga.src = "./example.jpg";
monitor.appendChild(imga);
*/

const idElementPrint = ref => {
  const iframe = document.createElement("iframe");
  iframe.style.display = "none";
  document.body.appendChild(iframe);
  const pri = iframe.contentWindow;
  pri.document.open();
  pri.document.write(ref.innerHTML);
  pri.document.close();
  pri.focus();
  pri.print();
  pri.onafterprint = () => { document.body.removeChild(iframe); }
}
Copilot answered 10/11, 2020 at 16:37 Comment(3)
Super clean answer, you may want to remove the element after : pri.onafterprint = () => { document.body.removeChild(ifram); }Aback
This worked, thanks!, but it is ignoring the CSS. do you know why? some sugestions?Stefanistefania
This only prints the text content of the element - no markup is preserved, which is not what most people are looking for. Swapping to document.write(ref.innerHTML) would work better.Boling
S
3

If you're using bootstrap, just add classname d-print-none to the elements you don't want to display in print

Snashall answered 17/8, 2021 at 14:37 Comment(1)
that's nice info ...Juni
P
2

If you are using JQuery, you can use clone to do the following:

function printElement(e) {
  var ifr = document.createElement('iframe');
  ifr.style='height: 0px; width: 0px; position: absolute'
  document.body.appendChild(ifr);

  $(e).clone().appendTo(ifr.contentDocument.body);
  ifr.contentWindow.print();

  ifr.parentElement.removeChild(ifr);
}

and use like so: printElement(document.getElementById('myElementToPrint'))

Powers answered 7/6, 2017 at 21:45 Comment(2)
hmm, adding stylesheets manually, but it still prints it without any styleMonochord
can you send example to recreate/illustrate?Powers
P
2

If I understood you well you can use CSS3 to print your selected HTML element.

@media print {
  body.print-element *:not(.print) {
    display: none;
  }
}

Notice, that you just need a selector. This allows you to easily print an element or the entire page using CSS classes.

Here you can check a working example: https://jsfiddle.net/gengns/d50m8ztu/

Plenteous answered 27/5, 2020 at 11:4 Comment(1)
This only works for direct children of body: if .print is not a direct child of body, all of its parents get display: none and are hidden. See jsfiddle.net/bzf92rj3Churchwarden
W
1

If you need to print the HTML element with pure JS, you can open a window that contains only the element you want to print (without any HTML-markup).

For instance, you can print the image itself without wrapping it in any HTML by opening this image in a new window as a file.

Note: 'visible=none' doesn't actually make the window invisible, but it allows to open it as a separate window (not a tab).

afterprint event allows us to close the window when the printing dialog is closed. event.target points to the opened window instance.

Note: afterprint MUST be assigned before calling .print(), otherwise it would not be called.

let win = window.open('/absolute/image/path.jpg', '__blank', 'visible=none');
win.addEventListener('afterprint', event => event.target.close() );
win.print();
Woodland answered 5/7, 2021 at 16:39 Comment(0)
M
0

Printing an Html or a Selected Html is easy using Print.Js Add Print.Js Library

http://printjs.crabbly.com/

  <form method="post" action="#" id="printJS-form">
    ...
  </form>

 <button type="button" onclick="printJS('printJS-form', 'html')">
    Print Form
 </button>
Melanous answered 11/12, 2018 at 12:26 Comment(0)
S
0

Add this method

function printDiv(divName) {   
        let specific_element = document.getElementById(divName).innerHTML;
        let original_elements = document.body.innerHTML;
    
        document.body.innerHTML = specific_element;
        window.print();
        document.body.innerHTML = original_elements;
    }
Segregationist answered 7/6, 2021 at 12:44 Comment(1)
The biggest problem I see with this approach is that all the event listeners from original elements will be gone.Respiratory
H
0

This implementation will create and apply an ad-hoc temporary style that hides all the elements on print media except the one that we want to print. After the printing the temporary style is removed, so your document will get back to its initial state.

Feel free to adjust the ad-hoc style (like papar size, margins, etc) to fit your needs.


/**
 * @description Print the given element using browser built-in function
 * @param {HTMLElement} element
 */
function printElement(element) {
  if (!element) {
    throw new Error(`Invalid print target element`);
  }

  const printWrapper = "print-wrapper";
  const printElement = "print-element";
  const css = `
  body.${printWrapper} *:not(.${printElement}) {
    visibility:hidden;
  }
  body.${printWrapper} .${printElement} {
    width: 210mm;
    height: 297mm;
    left:0;
    top:0;
    position:fixed;
  }
  body.${printWrapper} .${printElement} * {
    visibility:initial;
    margin: 0;
  }
  `;

  const head = document.getElementsByTagName("head")[0];
  const style = document.createElement("style");

  style.setAttribute("type", "text/css");
  style.setAttribute("media", "print");

  if (style.styleSheet) {
    style.styleSheet.cssText = css;
  } else {
    style.appendChild(document.createTextNode(css));
  }

  head.appendChild(style);

  document.body.classList.add(printWrapper);
  element.classList.add(printElement);

  window.print();

  document.body.classList.remove(printWrapper);
  element.classList.remove(printElement);

  head.removeChild(style);
}
Harrisonharrod answered 20/2, 2022 at 19:27 Comment(0)
B
0
  function printDomElement(element) {
    element.classList.add("printCss");

    let printId = "printSvgId";
    let name = ".printCss";
    let rules = "-webkit-print-color-adjust:exact;height:100%;width:100%;position:fixed;top:0;left:0;margin:0;";

    var style = document.createElement('style');
    style.id = printId;
    style.media = "print";
    document.getElementsByTagName('head')[0].appendChild(style);

    if (!(style.sheet || {}).insertRule)(style.styleSheet || style.sheet).addRule(name, rules);
    else style.sheet.insertRule(name + "{" + rules + "}", 0);

    window.print();

    setTimeout(() => {
      element.classList.remove("printCss");
      let elem = document.getElementById(printId);
      if (elem) elem.remove();
    }, 500);

  }
Baskett answered 17/8, 2022 at 3:25 Comment(1)
Good answers include some explanation, not just a block of code.Physiognomy
P
0

The example below is where you can click on a button, like with Button 1 text, and ONLY that button will appear. Some notes about my solution which was tested on my Mac including on Safari, Firefox, Chrome, and Edge browsers:

  • When a button tag is clicked:
    • hideAllElemsOnPrint JS function:
      All HTML elements (excluding the html tag) have a .hide-print class added that hides elements with a @media print {...} media query in the CSS with display: none;
    • onPrintEvents and updateParentElemClasses JS functions:
      ONLY the button tag that is clicked (and all parent tags that enclose the this button tag) have the .hide-print class removed and .show-print class added
    • The .show-print class does NOTHING but make my code easier to debug and has no styles in the CSS
    • exitPrintEvents JS function:
      Runs when you see the print dialogue popup and AFTER you click on the Cancel or Print buttons in the dialogue and .show-print and .hide-print classes are removed from all elements

const btns = document.querySelectorAll('button');

function onPrintEvents(btns, showPrintClass, hidePrintClass) {  
  btns.forEach((btn) => {    
   btn.addEventListener('click', (e) => {     
    const allElems = document.querySelectorAll('*');
    hideAllElemsOnPrint(allElems);   
     
    const currentBtn = e.target;
    currentBtn.classList.remove('hide-print'); 
    currentBtn.classList.add('show-print');
     
    updateParentElemClasses(currentBtn, showPrintClass, hidePrintClass);
    window.print();
   });
  });  
}

function exitPrintEvents(showPrintClass, hidePrintClass) {
  const afterPrint = function () {
    const printableElemsArr = Array.from(document.getElementsByClassName(showPrintClass));
    const notPrintableElemsArr = Array.from(document.getElementsByClassName(hidePrintClass));
    
    const elems = [...printableElemsArr, ...notPrintableElemsArr];
    
    elems.forEach((elem) => {
      elem.classList.remove(showPrintClass);
      elem.classList.remove(hidePrintClass);
    });
  };

  const mediaQueryList = window.matchMedia('print');

  mediaQueryList.addListener(function (e) {
    if (!e.matches) {
      afterPrint();
    }
  });
}

function updateParentElemClasses(elem, addClass, removeClass) {
  let getParent = elem.parentNode;
  getParent.classList.add(addClass);
  getParent.classList.remove(removeClass);
  let parentNodeName = getParent.nodeName.toUpperCase();

  while(parentNodeName) {    
    if(parentNodeName === 'BODY' || !parentNodeName) {
      break;
    }

    getParent = getParent.parentNode;
    getParent.classList.add(addClass);
    getParent.classList.remove(removeClass);
    parentNodeName = getParent?.nodeName.toUpperCase();     
  }  
}

function hideAllElemsOnPrint(allElems) {
  allElems.forEach((elem) => {
    const nodeTag = elem.nodeName.toUpperCase();

    if(nodeTag !== 'HTML') {
      elem.classList.remove('show-print');
      elem.classList.add('hide-print');
    }
  });  
}

onPrintEvents(btns, 'show-print', 'hide-print');
exitPrintEvents('show-print', 'hide-print');
.parent {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  border: 5px solid blue;
  gap: 10px;
}

.child {
  height: 100px;
  background-color: green;
  border: 1px solid yellow;
}

button {
  width: 100%;
  height: 100%;
  font-size: 2rem;
}

.purple-bg {
  background-color: purple;
}

.red-bg {
  background-color: red;
}

.deeppink-bg {
  background-color: deeppink;
}

.lightsalmon-bg {
  background-color: lightsalmon;
}

@media print {
  body {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  
  .hide-print {
    display: none;
  }
}
<h1>Print Clicked Button Element ONLY</h1>

<div class="parent">
  <div class="child">
    <button class="purple-bg">Button 1</button>
  </div>
  
  <div class="child">
    <button class="red-bg">Button 2</button>
  </div>
  
  <div class="child">
    <button class="deeppink-bg">Button 3</button>
  </div>
  
  <div class="child">
    <button class="lightsalmon-bg">Button 4</button>
  </div>  
</div>
Penhall answered 8/11, 2023 at 3:40 Comment(0)
D
0

Another workable way I found using Javascript is to, basically, temporary set the CSS display attribute for elements with the class "no-print" to none. Then call window.print(). It prints without those elements. After that, reset the original display attributes to each.

e.g., on clicking a "print' button,

printButton.addEventListener("click", () => {
    const noPrint = [...document.getElementsByClassName("no-print")];
    const property = [];
    noPrint.forEach((item) => {
        property.push(item.style.getPropertyValue("display"));
        item.style.setProperty("display", "none");
    });
    window.print();
    noPrint.forEach((item) => {
        item.style.setProperty("display", property.shift());
    });
});
Dremadremann answered 28/2 at 17:29 Comment(0)
A
0

As an extension to Gaurav's and Johny English's superb answers there is an unanswered question as to why the styles in the iframe are not the same.

This is because the iframe does not inherit its styles from the surrounding page. It is its own document, so you need to start afresh.

Two additional things need to be done:

  1. Replicate the styles in the parent document to the iframe
  2. Wait for the styles to load

In the case of (1) we can extract the elements from the main document with something like this:

var links = '';
document.querySelectorAll('head > link').forEach(css => {links += css.outerHTML});

In the case of (2) we could the same as Guarav, by adding a timer to allow content to load, but this is unreliable. A better way is to use the DOMContentLoaded. The iframe's DOMContentLoaded gets triggered after win.document.close(); as soon as all the resources of the freshly written document are loaded. After much experimentation, it appears the only way to reliably attach DOMContentLoaded is from within the iframe document itself.

So the finished function looks like this (I use CSP, so I need to know about the nonce):

function printElement(e, nonce) {
    var iframe = document.createElement("iframe");
    iframe.style.display = "none";
    document.body.appendChild(iframe);
    var win = iframe.contentWindow;                  
    win.document.open();
    // Copy the links
    var links = '';
    document.querySelectorAll('head > link').forEach(css => {links += css.outerHTML});
    // Set up content loaded event listener
    links += '<script nonce="' + nonce + '">' + 
        'document.addEventListener("DOMContentLoaded", (event) => {' +
        'window.focus();' +
        'window.print();' +
        '});' +
        '</script>';
    win.document.write('<html><head>' + links + '</head><body>' + e.outerHTML + '</body></html>');
    win.document.close(); 
    win.onafterprint = function(){ document.body.removeChild(iframe); };
}
Autumn answered 23/4 at 8:11 Comment(0)
H
0

If you need to exclude some parts of a document from printing, you can simply add a common class name called .no-print then you just need to specify the media type in your CSS and in our case it should be print and the last step will be using the classname in each element to be excluded.

Example:

@media print {
    .no-print {
        display: none;
    }
}

<div class="no-print">Exclude me from Printing</div>
<div class="no-print">Me too please</div>

Hope this could be useful for you guys !

Hinge answered 23/4 at 17:59 Comment(0)
I
-1

The simplest way to do it is:

elem = document.getElementById('elem').outerHTML

orig = document.documentElement.outerHTML

document.documentElement.outerHTML=elem
print()

document.documentElement.outerHTML = orig
Inequality answered 14/4, 2021 at 19:35 Comment(1)
That breaks all event listeners. So basically, the page will become completely unusable after this.Scrumptious
C
-1

Set the style of the element you want to print to position:fixed,then make it cover the whole page.

Cingulum answered 1/11, 2022 at 7:29 Comment(1)
Unreliable as content "behind" might "spill" from the bottom if it's taller than what you actually want to print or worse, cause a repeated content page printingDeckard
G
-7

Here is another (perhaps a more modern?) solution:

<link rel="stylesheet" media="print" href="print.css">
Gastroenterostomy answered 27/1, 2017 at 2:24 Comment(1)
This isn't really an answer - it provides nothing other than a linked style sheet. Please give us the rest of the answer.Upton

© 2022 - 2024 — McMap. All rights reserved.