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>
.
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>
display: normal
doesn't exist. I wish there was a generic option to turn on elements –
Cathey <link rel="stylesheet" media="mediatype and|not|only (expressions)" href="print.css">
? –
Gastroenterostomy media
attribute on the stylesheet link. –
Graham media="print"
i know –
Gastroenterostomy If you are familiar to jQuery, you can use jQuery Print Element plugin like this:
$('SelectorToPrint').printElement();
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
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
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); }
}
pri.onafterprint = () => { document.body.removeChild(ifram); }
–
Aback document.write(ref.innerHTML)
would work better. –
Boling If you're using bootstrap, just add classname d-print-none to the elements you don't want to display in print
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'))
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/
body
: if .print
is not a direct child of body
, all of its parents get display: none
and are hidden. See jsfiddle.net/bzf92rj3 –
Churchwarden 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();
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>
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;
}
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);
}
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);
}
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 thehtml
tag) have a.hide-print
class added that hides elements with a@media print {...}
media query in the CSS withdisplay: none;
onPrintEvents
andupdateParentElemClasses
JS functions:
ONLY thebutton
tag that is clicked (and all parent tags that enclose the thisbutton
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 theCancel
orPrint
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>
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());
});
});
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:
- Replicate the styles in the parent document to the iframe
- 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); };
}
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 !
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
Set the style of the element you want to print to position:fixed,then make it cover the whole page.
Here is another (perhaps a more modern?) solution:
<link rel="stylesheet" media="print" href="print.css">
© 2022 - 2024 — McMap. All rights reserved.