541

How do I print the indicated div (without manually disabling all other content on the page)?

I want to avoid a new preview dialog, so creating a new window with this content is not useful.

The page contains a couple of tables, one of them contains the div I want to print - the table is styled with visual styles for the web, that should not show in print.

Pikamander2
  • 7,332
  • 3
  • 48
  • 69
noesgard
  • 5,917
  • 3
  • 20
  • 27
  • 1
    http://stackoverflow.com/questions/2255291/print-the-contents-of-a-div#answer-2255438 this link works perfect – Jinna Balu Mar 13 '17 at 18:42

33 Answers33

997

Here is a general solution, using CSS only, which I have verified to work.

@media print {
  body {
    visibility: hidden;
  }
  #section-to-print {
    visibility: visible;
    position: absolute;
    left: 0;
    top: 0;
  }
}

There's a Code Sandbox if you want to see this in action. Click the Open In New Window button above the preview; then you can use the browser's Print command to see a preview of the printout.

Alternative approaches aren't so good. Using display is tricky because if any element has display:none then none of its descendants will display either. To use it, you have to change the structure of your page.

Using visibility works better since you can turn on visibility for descendants. The invisible elements still affect the layout though, so I move section-to-print to the top left so it prints properly.

Bennett McElwee
  • 24,740
  • 6
  • 54
  • 63
  • `#section_to_print` should work better with `position:static;` instead of `position:absolute;` – vitto Jan 24 '11 at 14:22
  • How is it better? Multi-page printing, perhaps? – Bennett McElwee Feb 07 '11 at 22:39
  • 34
    this is by far the fastest and cleanest way, i wonder why this answer didn't get the most votes -.- – Dany Khalife Nov 06 '11 at 21:14
  • 44
    A problem to watch out for with this solution is that you can end up printing thousands of blank pages in some cases. In my case I was able to solve this by using some additional display:none styling for selected items but perhaps a more general solution is achievable by some combination of also forcing heights, overflow:none and absolute positioning for all divs or something. – Malcolm MacLeod May 17 '13 at 05:52
  • You're right: if the content spans multiple pages then you have to be careful with the CSS. And test in every possible browser. :\ – Bennett McElwee May 17 '13 at 09:36
  • 7
    This is a great start but I had two troubles with it: for one if any of the element's parents established its own relative/absolute positioning the content would still be offset unless I used `position:fixed` instead. However, Chrome and Safari would also truncate content, especially after the first page. So my final workaround was to set both the target *and* _all its parents_ to `overflow:visible; position:absolute !important; top:0;left:0` – natevw Dec 13 '13 at 22:00
  • @Bennett thanks for this excellent solution. But I am getting an extra blank page when I print. How can we avoid that? – sanjeev May 08 '14 at 17:27
  • @sanjeev First step: test results on various different browsers, to see if the problem is browser-dependent. – Bennett McElwee May 08 '14 at 21:35
  • @Bennett Problem is not browser dependent. I can see it in Chrome, FF and IE. – sanjeev May 09 '14 at 16:31
  • @sanjeev I created a minimal [Plunk](http://plnkr.co/edit/ceY5AaRk0j5HgQkcVzwt?p=preview) that works for me in Chrome (it prints out a single page). Maybe you could create a Plunk that demonstrates the problem, and we could figure out what's going on. – Bennett McElwee May 12 '14 at 01:07
  • Curious, why does section-to-print need to be present twice? – dudeNumber4 Jul 13 '15 at 13:11
  • @dudeNumber4 The second rule makes the print section and its contents visible. The third rule moves the print section to the top-left corner. You could refactor the rules to reduce the selector duplication, but you'd have to duplicate the visibility declaration instead. – Bennett McElwee Jul 13 '15 at 21:09
  • @BennettMcElwee No, I mean why does the second rule have to reference the Id selector twice? – dudeNumber4 Jul 14 '15 at 14:06
  • 1
    @dudeNumber4 `#section-to-print` matches the section itself; `#section-to-print *` matches each sub-element of the section. So that rule just makes the section and all its contents visible. – Bennett McElwee Jul 14 '15 at 21:54
  • @BennettMcElwee: What if the section-to-print div is on the bottom right corner of the page ? And the div position is relative meaning it adjusts according to the page size ? – Vicky Sep 29 '15 at 13:26
  • @Vicky When printed, it will move to the top left. – Bennett McElwee Sep 30 '15 at 05:08
  • 1
    As noted above, this does not work on more complex pages with lots of content. If you need to completely block content from displaying using display:none, you may be better off with a js solution – ilektron Mar 12 '16 at 20:56
  • 3
    You can try a JavaScript solution, but that won't work if your user uses the browser's Print command. – Bennett McElwee Mar 15 '16 at 00:37
  • But it avoids the css styles from external bootstrap file. – mpsbhat Aug 03 '16 at 00:11
  • It is still using the Bootstrap styles. Bootstrap is setting the text to black when printing, via the rule in `print.less`. – Bennett McElwee Aug 03 '16 at 00:49
  • Can you explain how I use this in my page? I have a master CSS file – James Wierzba Aug 10 '16 at 14:25
  • @JamesWierzba (Not sure what you mean by a master CSS file) Put the CSS snippet in your CSS file and change `#section-to-print` to a selector that selects the section you want to print. – Bennett McElwee Aug 10 '16 at 22:48
  • 1
    6 years later this is still a perfect solution. I used this in an AngularJS application with window.print() and had no issues. – Alex Sep 09 '16 at 15:28
  • So I tried this and it works, but I don't understand how. I didn't apply #section-to-print to anything in my html. How exactly is this able to print exactly what I need? – ArtisanSamosa Dec 13 '16 at 17:03
  • It is possible that the bit you wanted already had `visibility: visible` set by some other CSS. – Bennett McElwee Dec 13 '16 at 23:08
  • I feel like `body *:not(#section-to-print *) {visibility: hidden;}` would be more elegant as it wouldn't require overriding things twice. However, it doesn't seem to work at all for me. Oh well. – Bryan Mar 19 '17 at 06:02
  • If there are absolutely placed elements in the section to be printed, you have to set them to hidden in the media print section of the css in order for this solution to work. The Material Design LiteTextField component is an example of this issue. – Lambert Aug 09 '17 at 12:51
  • I improved it a little bit, if you wanna hide the printable stuff. `#section-to-print{ visibility:hidden; height:0px; } @media print { body * { visibility: hidden; } #section-to-print, #section-to-print * { visibility: visible; } #section-to-print { position: absolute; left: 0; top: 0; } } ` – Shah Abaz Khan Nov 13 '17 at 09:38
  • @ShahAbazKhan If you want to hide the printable stuff on the screen, then simpler solutions are possible. But it's a bit weird: it means you'd see something on the screen, select "Print", and something completely different would appear at your printer. – Bennett McElwee Nov 13 '17 at 22:33
  • This fails when we are using div with the scrollbar – Jeevan Roy dsouza Oct 26 '18 at 04:32
  • @JeevanRoydsouza can you give an example? – Bennett McElwee Oct 26 '18 at 04:43
  • When we have section-to-print in @media print with .section-to-print, .section-to-print * { visibility: visible; } .section-to-print { position: fixed; left: 0; top: 0; display: block; width: auto; overflow-y: scroll; } and out side media print css .section-to-print{ height: 80%; overflow-y: scroll; border: 1px solid grey; } – Jeevan Roy dsouza Oct 26 '18 at 04:50
  • When we have section-to-print is a div with the scrollbar, then scrollbar is not coming in the print page – Jeevan Roy dsouza Oct 26 '18 at 04:52
  • To hide the printed area, use: @media screen { #section-to-print { display: none; } } – svenema Jan 08 '20 at 18:03
  • This solution works perfect, but unfortunately in my case I have page breaks (page-break-after:always) which is not working, it is because of position absolute. Any idea how to avoid using position absolute. – Rami Jul 07 '22 at 13:24
  • After spending 2 hours on finding a solution this worked – travelerrrrrrr Jul 19 '22 at 20:43
  • 1
    Why is `#section-to-print *` necessary? It seems solely `#section-to-print { visibility: visible; }` also works, since visibility inherits? – Jyunhao Shih Apr 24 '23 at 07:58
  • @JyunhaoShih You are right! You are the first person in 10 years to suggest that improvement. (Although dudeNumber4 hinted at it.) Thanks -- I don't know how that escaped me for so long. – Bennett McElwee Apr 25 '23 at 08:48
291

I have a better solution with minimal code.

Place your printable part inside a div with an id like this:

<div id="printableArea">
      <h1>Print me</h1>
</div>

<input type="button" onclick="printDiv('printableArea')" value="print a div!" />

Then add an event like an onclick (as shown above), and pass the id of the div like I did above.

Now let's create a really simple javascript:

function printDiv(divName) {
     var printContents = document.getElementById(divName).innerHTML;
     var originalContents = document.body.innerHTML;

     document.body.innerHTML = printContents;

     window.print();

     document.body.innerHTML = originalContents;
}

Notice how simple this is? No popups, no new windows, no crazy styling, no JS libraries like jquery. The problem with really complicated solutions (the answer isn't complicated and not what I'm referring to) is the fact that it will NEVER translate across all browsers, ever! If you want to make the styles different, do as shown in the checked answer by adding the media attribute to a stylesheet link (media="print").

No fluff, lightweight, it just works.

Kevin Florida
  • 6,659
  • 3
  • 23
  • 20
  • @Kevin i try this for form but it print empty form (without data) and i need a filled form to be print before submitting – Arif Mar 15 '12 at 12:29
  • This works perfectly fine in Fierfox and Chrome. For some reasons , IE hangs when opening and writing down the contents. – vsingh Apr 27 '12 at 19:38
  • @Kevin: Great solution.. However it does not capture the background colors and styles? It prints only plain text. Any modification possible for getting the colors and styles as well? – Anil Soman Aug 28 '12 at 07:43
  • 129
    @asprin warning! This is not mess free code. Using innerHTML to wipe out then recreate the whole body is fine for simple pages, but with more advanced customizations (menus, slideshows, etc.) it could erase some dynamic behaviors added by other scripts. – Christophe Nov 06 '12 at 18:31
  • 26
    This solution is not going to work in any complex page where the elements in printable area depend on styles and/or position of parent elements. If you extract the printable div, it may look totally different because all of the parents are now missing. – Andrei Volgin Dec 18 '12 at 07:12
  • 1
    Sadly doesn't work well in Chrome if you close the Print preview window then try to do a jQuery `.click`. It's a shame, because the code is so lightweight. – rybo111 Jul 11 '13 at 20:36
  • @Kevin Thank you very much. This is indeed the solution for my problem. No need to mess around with my code either, great answer! +1 – Paramone Jan 30 '14 at 14:05
  • I like the approach but against having to reload the entire dom just to print. In a complex page with 'state' this would be very tricky. I have been inspired by this code and come up with an alternative: https://github.com/mikeljames/printme – mike james Mar 11 '14 at 17:18
  • @mike You are not reloading anything, This is strictly manipulating DOM. You are storing the markup in a variable, printing the page and putting it back. I understand your hesitancy in doing this, but it is important to realize there is no loading taking place. You are simply manipulating DOM – Kevin Florida Mar 20 '14 at 15:01
  • @KevinFlorida When I say Reload I essentially mean repaint, the dom is slow, using css to hide the elements is faster: http://stackoverflow.com/questions/2447309/javascript-removechild-and-appendchild-vs-display-none-and-display-blockinl – mike james Mar 20 '14 at 16:13
  • @Christophe: My page on ASP.NET very heavy and contains a lot of dynamic content. Despite this, the printing function works great. The idea itself is simple and ingenious, thanks Kevin Florida! – Boris Gappov May 07 '15 at 13:25
  • 4
    @BorisGappov a very simple example with just one click event to prove my point: http://jsfiddle.net/dc7voLzt/ I'll say it again: this is not mess-free code! The issue is not with the print itself, it's about restoring the original page! – Christophe May 07 '15 at 20:09
  • 1
    with this solution when i click to print the page and close the preview window i cant click to print again, any idea why print() only works once ?, im using React with Redux. – DJeanCar Jul 13 '16 at 21:59
  • @Kevin I tried this code but having one problem that is page breaks are not working in print. I have page-break-after: always; in child elements of print div but still print does not have any page break :( – Nikhil Gaur Aug 08 '16 at 07:36
  • Hi @KevinFlorida I tried your code and it works only once. after closing and clicking again the button it shows error. I'm using vuejs2 Uncaught TypeError: Failed to execute 'contains' on 'Node': parameter 1 is not of type 'Node'. – Alyssa Reyes Apr 11 '17 at 04:24
  • If your html has select tag then it's not display the selected option while printing. – Maulik Mar 21 '18 at 09:45
  • What if I want to send a URL in the button and print the pdf of the URL? Is this possible? This is for the archive page. Note: I don't want to redirect to the URL I am sending. – Alisha Lamichhane Apr 08 '19 at 07:28
  • It didn't work in my case. I have a form to be printed and I tried ur trick. But it is giving me some errors like: `Cannot set property 'onclick' of null` and `Uncaught (in promise) Error: Not enough parameters.` BTW I am on AngularJS – Srk95 Nov 22 '19 at 08:27
  • I used location.reload(); at the last line to fix the onclick problem and this this way, the answer is totally fast and satisfying for me, thanks – Saghachi Dec 14 '20 at 08:52
  • I tried all options, this one works on Chrome. To make sure the switch back is working a location.reload() should be used – John Dec 29 '20 at 04:45
  • Plenty of scope to add styles before printing and restore them afterwards with this clear simple piece of code. Handles pages delivered by PHP just fine. Maybe `onfocus() location.reload()` for when the print dialogue is cancelled will help. – Steve Jan 26 '21 at 22:00
  • This is quick and good solution for small to medium sized pages.. well done!! – Thameem Feb 22 '21 at 12:44
  • Working fine for me in Chrome. – Arvind Kumar Sep 21 '22 at 09:45
131

All the answers so far are pretty flawed - they either involve adding class="noprint" to everything or will mess up display within #printable.

I think the best solution would be to create a wrapper around the non-printable stuff:

<head>
    <style type="text/css">

    #printable { display: none; }

    @media print
    {
        #non-printable { display: none; }
        #printable { display: block; }
    }
    </style>
</head>
<body>
    <div id="non-printable">
        Your normal page contents
    </div>

    <div id="printable">
        Printer version
    </div>
</body>

Of course this is not perfect as it involves moving things around in your HTML a bit...

Greg
  • 316,276
  • 54
  • 369
  • 333
  • I think you're right, but how do I kill the styling of the table surrounding the div (if thats possible to remove the styling - I can print the table and exclude the rest of the content quite easily – noesgard Jan 22 '09 at 12:32
  • I uses Javascript to pickup the needed content and the CSS like above – noesgard Feb 03 '09 at 13:07
  • 11
    I prefer using semantic HTML. Print formatting should ideally be handled by CSS. See my answer for how to do this: http://stackoverflow.com/questions/468881/print-div-idprintarea-div-only/2618980#2618980 – Bennett McElwee Apr 11 '10 at 22:42
  • Agree with Bennett, using visibility instead of display is a much cleaner solution – guigouz May 27 '11 at 02:33
  • I made a really simple solution at lower on this thread which I think will suit the asker's needs better. It doesn't rely on a print stylesheet, can be recycled all over your website, and is incredibly lightweight. – Kevin Florida Sep 23 '11 at 17:42
  • @BennettMcElwee But that doesn't allow you to dynamically change which parts of the page are printable based on other conditions, which is the only reason I imagine someone would be looking to JavaScript to achieve this goal. – Casey Jan 20 '15 at 18:47
  • @emodendroket Quite right, if you want to do dynamic things you'll need JavaScript.Using [my solution](http://stackoverflow.com/questions/468881/print-div-id-printarea-div-only/2618980#2618980), for instance, you could use JS to assign the `section-to-print` ID to whichever part of the page you want to print. That takes care of the dynamic aspect. Then the CSS takes care of the presentation (printing) aspect, as it should. – Bennett McElwee Jan 20 '15 at 21:14
  • @BennettMcElwee Sure. I agree, but I don't understand how that differs from this answer. – Casey Jan 20 '15 at 21:15
  • @emodendroket This answer requires you to structure the page in a certain way, and it requires you to create a separate "printer version" that isn't shown on-screen at all. (Thus it doesn't even answer the OP's question!) – Bennett McElwee Jan 20 '15 at 21:32
  • @BennettMcElwee Oh, I see what you mean. Yeah, you're right that styling body as hidden is probably cleaner. – Casey Jan 20 '15 at 21:33
117

With jQuery it's as simple as this:

w=window.open();
w.document.write($('.report_left_inner').html());
w.print();
w.close();
romaninsh
  • 10,606
  • 4
  • 50
  • 70
  • 3
    This is pretty cool, altho it shows up in Chrome as a blocked popup. – Rafi Jacoby Jun 09 '11 at 21:40
  • 9
    the trick is to call it on user-generated event such as on mouse click. you can also add after first line: if(!w)alert('Please enable pop-ups'); – romaninsh Jun 09 '11 at 22:54
  • Definitely adding this to my toolkit. It is a quick and simple solution. – None Sep 03 '12 at 04:29
  • OP wanted not to include the web-styling, but I suppose we can add few – romaninsh Mar 12 '13 at 12:13
  • 1
    has anyone got this working on IE11? It just opens a window then closes it immediately. Works in Chrome, FF and safari though. – greatwitenorth Jul 06 '15 at 21:17
  • Thank you but I have a question. All objects in page acts like left-to-right. Is there a way to prevent it ? @romaninsh – Koray Durudogan Jan 29 '16 at 09:14
  • 3
    I lost the css while printing with this, is there any way to maintain css? – Moxet Khan Apr 21 '16 at 10:10
  • 2
    @MoxetKhan, this post has a solution with css http://vevlo.com/how-to-print-div-content-using-javascript/ – Evgenia Karunus Apr 29 '18 at 10:56
  • 1
    Here's a implementation in pure javascript: `function print(id) { var content = document.getElementById(id).cloneNode(true); var w = window.open(); w.document.head.innerHTML = document.getElementsByTagName("head")[0].innerHTML; w.document.body.append(content); w.print(); w.close(); }` – Y Stroli Jul 08 '21 at 00:31
  • @romaninsh sir i received null after window.open can you tell me how to fix? – Kapil Soni Oct 21 '21 at 07:34
22

Could you use a print stylesheet, and use CSS to arrange the content you wanted printed? Read this article for more pointers.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • I do have a print style sheet - trying to avoid putting a style rule in all other content... – noesgard Jan 22 '09 at 12:18
  • I do have a table with styling on, containg the div in question, If I set the table to display:none - can I still display the div? – noesgard Jan 22 '09 at 12:27
  • I think so yes, and you could try marking the rule as !important to boost it! – Paul Dixon Jan 22 '09 at 12:46
  • if the table isn't displayed it won't matter even if the div is set to 'display: awesome;'. The parent is hidden and so are the children. Is this a situation where you need a table or is it just for page layout? – roborourke Jan 22 '09 at 17:29
  • "Boom, headshot!" by table layouts. =| – ANeves May 05 '10 at 13:03
18

I didn't really like any of these answers as a whole. If you have a class (say printableArea) and have that as an immediate child of body, then you can do something like this in your print CSS:

body > *:not(.printableArea) {
    display: none;
}

//Not needed if already showing
body > .printableArea {
    display: block;
}

For those looking for printableArea in another place, you would need to make sure the parents of printableArea are shown:

body > *:not(.parentDiv),
.parentDiv > *:not(.printableArea) {
    display: none;
}

//Not needed if already showing
body > .printableArea {
    display: block;
}

Using the visibility can cause a lot of spacing issues and blank pages. This is because the visibility maintains the elements space, just makes it hidden, where as display removes it and allows other elements to take up its space.

The reason why this solution works is that you are not grabbing all elements, just the immediate children of body and hiding them. The other solutions below with display css, hide all the elements, which effects everything inside of printableArea content.

I wouldn't suggest javascript as you would need to have a print button that the user clicks and the standard browser print buttons wouldn't have the same effect. If you really need to do that, what I would do is store the html of body, remove all unwanted elements, print, then add the html back. As mentioned though, I would avoid this if you can and use a CSS option like above.

NOTE: You can add whatever CSS into the print CSS using inline styles:

<style type="text/css">
@media print {
   //styles here
}
</style>

Or like I usually use is a link tag:

<link rel="stylesheet" type="text/css" media="print" href="print.css" />
fanfavorite
  • 5,128
  • 1
  • 31
  • 58
  • What if the div you want to print is not "an immediate child of body"? I'm trying to do this in vue.js.. But I'm getting a lot of blank pages when using the accepted answer. – svenema Jan 08 '20 at 20:47
  • @svenema, you can use any CSS you want. This was just an example. – fanfavorite Jan 09 '20 at 03:17
  • 1
    hmm, still, when I try this, there are indeed no additional blank pages, but the printableArea div is also not showing; I just have 1 empty blank page when I use this code. – svenema Jan 09 '20 at 07:15
  • I found out that it is indeed because the printableArea div is not a direct child of the body tag, when I make it a direct child your solution works; however, in my case I cannot make the printableArea a direct child. Is there a way around this? – svenema Jan 09 '20 at 09:40
  • still.. when the printableArea div is *not* a direct child of the body tag I get a blank page only. Could you post a fully working example perhaps? – svenema Jan 09 '20 at 15:08
  • If you post your example to jsfiddle or something similar, I can help fix. – fanfavorite Jan 10 '20 at 16:18
  • Sorry for the delay. The site wasn't working when I had time to look and just got back to this. Basically you need to specify the parent in your CSS. Something like https://jsfiddle.net/sn79fow1/ – fanfavorite Jan 17 '20 at 22:21
  • Great stuff, very much appreciated! I've been playing with it for a few hours now, learning about the selectors and pseudo classes. But I've not been able to figure out if there is a way to place the printableArea in an arbitrary location and still have it only print that specific class. – svenema Jan 18 '20 at 14:37
10

Step 1: Write the following javascript inside your head tag

<script language="javascript">
function PrintMe(DivID) {
var disp_setting="toolbar=yes,location=no,";
disp_setting+="directories=yes,menubar=yes,";
disp_setting+="scrollbars=yes,width=650, height=600, left=100, top=25";
   var content_vlue = document.getElementById(DivID).innerHTML;
   var docprint=window.open("","",disp_setting);
   docprint.document.open();
   docprint.document.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"');
   docprint.document.write('"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
   docprint.document.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">');
   docprint.document.write('<head><title>My Title</title>');
   docprint.document.write('<style type="text/css">body{ margin:0px;');
   docprint.document.write('font-family:verdana,Arial;color:#000;');
   docprint.document.write('font-family:Verdana, Geneva, sans-serif; font-size:12px;}');
   docprint.document.write('a{color:#000;text-decoration:none;} </style>');
   docprint.document.write('</head><body onLoad="self.print()"><center>');
   docprint.document.write(content_vlue);
   docprint.document.write('</center></body></html>');
   docprint.document.close();
   docprint.focus();
}
</script>

Step 2: Call the PrintMe('DivID') function by an onclick event.

<input type="button" name="btnprint" value="Print" onclick="PrintMe('divid')"/>
<div id="divid">
here is some text to print inside this div with an id 'divid'
</div>
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Hardik Thaker
  • 3,050
  • 1
  • 27
  • 37
  • 1
    This is the one! Used it for a Modal and Gallerys. No Javascript errors after closing. Really helpful especially when u use modals which are longer than one page. Nicely wraps it up. Perfect for people who want to print to store. – TheWeeezel Dec 13 '16 at 23:47
10
  1. Give whatever element you want to print the id printMe.

  2. Include this script in your head tag:

    <script language="javascript">
        var gAutoPrint = true;
    
        function processPrint(){
    
        if (document.getElementById != null){
        var html = '<HTML>\n<HEAD>\n';
        if (document.getElementsByTagName != null){
        var headTags = document.getElementsByTagName("head");
        if (headTags.length > 0) html += headTags[0].innerHTML;
        }
    
        html += '\n</HE' + 'AD>\n<BODY>\n';
        var printReadyElem = document.getElementById("printMe");
    
        if (printReadyElem != null) html += printReadyElem.innerHTML;
        else{
        alert("Error, no contents.");
        return;
        }
    
        html += '\n</BO' + 'DY>\n</HT' + 'ML>';
        var printWin = window.open("","processPrint");
        printWin.document.open();
        printWin.document.write(html);
        printWin.document.close();
    
        if (gAutoPrint) printWin.print();
        } else alert("Browser not supported.");
    
        }
    </script>
    
  3. Call the function

    <a href="javascript:void(processPrint());">Print</a>
    
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
  • This is a good job. But way too complicated and will not work properly cross-browser (especially older browsers). I suggest you take a look at my solution below. – Kevin Florida Sep 23 '11 at 17:20
7
<script type="text/javascript">
   function printDiv(divId) {
       var printContents = document.getElementById(divId).innerHTML;
       var originalContents = document.body.innerHTML;
       document.body.innerHTML = "<html><head><title></title></head><body>" + printContents + "</body>";
       window.print();
       document.body.innerHTML = originalContents;
   }
</script>

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Dilip Kr Singh
  • 1,418
  • 1
  • 18
  • 26
6

hm ... use the type of a stylsheet for printing ... eg:

<link rel="stylesheet" type="text/css" href="print.css" media="print" />

print.css:

div { display: none; }
#yourdiv { display: block; }
  • This will not work if the document is not DIV-based or #yourdiv also includes further DIVs. – Gumbo Jan 22 '09 at 12:18
  • #yourdiv * { display: ... } if you place this on top of the page and have an up-to-date browser you can then work with more selectors to hide away non divs –  Jan 22 '09 at 12:20
  • "#yourdiv * { display: ... }" - what should the ... be without breaking the layout? – Greg Jan 22 '09 at 12:21
  • This would display inline elements also as block elements. But “#yourdiv, #yourdiv div { display:block }” will do it. – Gumbo Jan 22 '09 at 12:23
  • @dittodhole - think about it for a minute. What could you put in there that won't break the layout within #yourdiv? – Greg Jan 22 '09 at 12:30
  • run-in - but not supported with common browsers. only working values are: inline, block and none (list-item with ie > 5). so i would say: it depends on the layout! but i would prefer Gumbo's solution with my not-knowing-what's-on-the-page view –  Jan 22 '09 at 12:35
  • The trouble is, with almost any layout you have a mix of block and inline. Even something really simple like this:

    This is broken.

    If you choose inline or block

    – Greg Jan 22 '09 at 12:38
  • therefore i would tend to build up 2 different mother-divs like here http://stackoverflow.com/questions/468881/print-div-idprintarea-div-only#468922 –  Jan 22 '09 at 12:45
6

The Best way to Print particular Div or any Element

printDiv("myDiv");

function printDiv(id){
        var printContents = document.getElementById(id).innerHTML;
        var originalContents = document.body.innerHTML;
        document.body.innerHTML = printContents;
        window.print();
        document.body.innerHTML = originalContents;
}
qɐʇǝɥɐW
  • 347
  • 3
  • 17
  • This solution of overwriting the whole page sometimes doesn't work, for example in APEX the menu stops working. – Tomasz Jan 16 '22 at 22:02
  • hmm, may your event listener stop working, you can write event like ```$(document).on("click","#element",function(){ /*some code*/ });``` , may it will help you or plz, describe or show your example... :) – qɐʇǝɥɐW Jan 21 '22 at 07:56
  • menu in oracle apex stops working after printing. ;( – Tomasz Feb 04 '22 at 15:31
6

Without CSS clowning, html and pure javascript with iframe does its work best. Then simply click the text, you want to print. Current example for id elements with text content;

html body:

<div id="monitor" onclick="idElementPrint()">text i want to print</div>

pure javascript:

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

const idElementPrint = () => {
    let ifram = document.createElement("iframe");
    ifram.style = "display:none";
    document.body.appendChild(ifram);
    pri = ifram.contentWindow;
    pri.document.open();
    pri.document.write(monitor.textContent);
    pri.document.close();
    pri.focus();
    pri.print();
    }
Johny English
  • 166
  • 3
  • 6
3

printDiv(divId): A generalized solution to print any div on any page.

I had a similar issue but I wanted (a) to be able to print the whole page, or (b) print any one of several specific areas. My solution, thanks to much of the above, allows you to specify any div object to be printed.

The key for this solution is to add an appropriate rule to the the print media style sheet so that the requested div (and its contents) will be printed.

First, create the needed print css to suppress everything (but without the specific rule to allow the element you want to print).

<style type="text/css" media="print">
   body {visibility:hidden; }
   .noprintarea {visibility:hidden; display:none}
   .noprintcontent { visibility:hidden; }
   .print { visibility:visible; display:block; }
</style>

Note that I have added new class rules:

  • noprintarea allows you to suppress the printing of elements within your div- both the content and the block.
  • noprintcontent allows you to suppress the printing of elements within your div- the content is suppressed but and the allocated area is left empty.
  • print allows you to have items that show up in the printed version but not on the screen page. These will normally have "display:none" for the screen style.

Then insert three JavaScript functions. The first merely toggles the print media style sheet on and off.

function disableSheet(thisSheet,setDisabled)
{ document.styleSheets[thisSheet].disabled=setDisabled; }   

The second does the real work and the third cleans up afterward. The second (printDiv) activates the print media style sheet, then appends a new rule to allow the desired div to print, issues the print, and then adds a delay before the final housekeeping (otherwise the styles can be reset before the print is actually done.)

function printDiv(divId)
{
  //  Enable the print CSS: (this temporarily disables being able to print the whole page)
  disableSheet(0,false);
  //  Get the print style sheet and add a new rule for this div
  var sheetObj=document.styleSheets[0];  
  var showDivCSS="visibility:visible;display:block;position:absolute;top:30px;left:30px;";
  if (sheetObj.rules) { sheetObj.addRule("#"+divId,showDivCSS); }
  else                { sheetObj.insertRule("#"+divId+"{"+showDivCSS+"}",sheetObj.cssRules.length); }
  print();
  //  need a brief delay or the whole page will print
  setTimeout("printDivRestore()",100);  
}

The final functions deletes the added rule and sets the print style again to disabled so the whole page can be printed.

function printDivRestore()
{
  // remove the div-specific rule
  var sheetObj=document.styleSheets[0];  
  if (sheetObj.rules) { sheetObj.removeRule(sheetObj.rules.length-1); }
  else                { sheetObj.deleteRule(sheetObj.cssRules.length-1); }
  //  and re-enable whole page printing
  disableSheet(0,true);
}

The only other thing to do is to add one line to your onload processing so that the print style is initially disabled thereby allowing whole page printing.

<body onLoad='disableSheet(0,true)'>

Then, from anywhere in your document, you can print a div. Just issue printDiv("thedivid") from a button or whatever.

A big plus for this approach it provides a general solution to printing selected content from within a page. It also allows use of existing styles for elements that are printed - including the containing div.

NOTE: In my implementation, this must be the first style sheet. Change the sheet references (0) to the appropriate sheet number if you need to make it later in the sheet sequence.

DrDave
  • 718
  • 1
  • 7
  • 16
2

Sandro's method works great.

I tweaked it to allow for allowing multiple printMe links, particularily to be used in tabbed pages and expanding text.

function processPrint(printMe){ <-- calling for a variable here

var printReadyElem = document.getElementById(printMe); <-- removed the quotes around printMe to ask for a variable

<a href="javascript:void(processPrint('divID'));">Print</a> <-- passing the div ID to be printed on to the function to turn the printMe variable into the div ID. single quotes are needed

2

@Kevin Florida If you have multiple divs with same class, you can use it like this:

 <div style="display:none">
   <div id="modal-2" class="printableArea">
     <input type="button" class="printdiv-btn" value="print a div!" />
   </div>
 </div>

i was using Colorbox inner content type

$(document).on('click', '.printdiv-btn', function(e) {
    e.preventDefault();

    var $this = $(this);
    var originalContent = $('body').html();
    var printArea = $this.parents('.printableArea').html();

    $('body').html(printArea);
    window.print();
    $('body').html(originalContent);
});
Stefan
  • 627
  • 6
  • 19
2

In my case I had to print a image inside a page. When I used the solution voted, I had 1 blank page and the other one showing the image. Hope it will help someone.

Here is the css I used:

@media print {
  body * {
    visibility: hidden;
  }

  #not-print * {
    display: none;
  }

  #to-print, #to-print * {
    visibility: visible;
  }

  #to-print {
    display: block !important;
    position: absolute;
    left: 0;
    top: 0;
    width: auto;
    height: 99%;
  }
}

My html is:

<div id="not-print" >
  <header class="row wrapper page-heading">

  </header>

  <div class="wrapper wrapper-content">
    <%= image_tag @qrcode.image_url,  size: "250x250" , alt: "#{@qrcode.name}" %>
  </div>
</div>

<div id="to-print" style="display: none;">
  <%= image_tag @qrcode.image_url,  size: "300x300" , alt: "#{@qrcode.name}" %>
</div>
2

One more approch without affecting current page and it also persist the css while printing. Here selector must be specific div selector which content we need to print.

printWindow(selector, title) {
   var divContents = $(selector).html();
   var $cssLink = $('link');
   var printWindow = window.open('', '', 'height=' + window.outerHeight * 0.6 + ', width=' + window.outerWidth  * 0.6);
   printWindow.document.write('<html><head><h2><b><title>' + title + '</title></b></h2>');
   for(var i = 0; i<$cssLink.length; i++) {
    printWindow.document.write($cssLink[i].outerHTML);
   }
   printWindow.document.write('</head><body >');
   printWindow.document.write(divContents);
   printWindow.document.write('</body></html>');
   printWindow.document.close();
   printWindow.onload = function () {
            printWindow.focus();
            setTimeout( function () {
                printWindow.print();
                printWindow.close();
            }, 100);  
        }
}

Here provided some time out show that external css get applied to it.

2

All answers have trade-offs and cannot be used for all cases. They fall into 3 categories:

  1. Use a printing style sheet. This requires building the whole website to be print-aware.

  2. Hide all elements in <body> and only show the printable element. This works nicely for simple pages, but it is tricky for complex pages.

  3. Open a new window with the content of the printable element or replace the <body> content with the content of the element. The first will lose all styles, and the second is messy and can break events.

There is no one solution that will work well for all cases, so it is good to have all those choices and I'm adding another solution that works much better in some cases. This solution is a hybrid of two categories: hide all content of <body>, then copy the content of the printable element to a new <div> and append it to <body>. After printing, remove the newly added <div> and show the content of <body> back. This way, you won't lose the styles or events, and you don't mess up with opening a new window. But like all other solutions, it won't work well for all cases. If your printable element's styles depends on its parents, you'll lose those styles. It is still much easier to style your printable elements independently from its parents than having to style the entire website for printing.

The only hurdle is figuring out how to select all content of <body>. For simple pages, the generic style body>* will do the trick. However, complex pages usually have <script> tags at the end of body' and also some `s that are used for dialogs, etc. Hiding all those is fine, but you don't want to show them after printing.

In my case, I build all may websites with three sections inside <body>: <header>, <footer>, and between them <div id="Content">. Adjust the first line of the function below for your case:

function PrintArea(selector) {
    //First hide all content in body.
    var all = $("body > header, body > #Content, body > footer")
    all.hide();
    //Append a div for printing.
    $("body").append('<div id="PrintMe">');
    //Copy content of printing area to the printing div.
    var p = $("#PrintMe");
    p.html($(selector).html());
    //Call the print dialog.
    window.print();
    //Remove the printing div.
    p.remove();
    //Show all content in body.
    all.show();
}

I used jQuery because it's cleaner and simpler, but you can easily convert it to vanilla JavaScript if you like. And of course, you can change var to let as recommended for the local variables.

Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
2
It's better solution. You can use it Angualr/React

Html

 <div class="row" id="printableId">
      Your html 
    </div>

Javascript

   function printPage(){
        
        var printHtml = window.open('', 'PRINT', 'height=400,width=600');
    
        printHtml.document.write('<html><head>');
        printHtml.document.write(document.getElementById("printableId").innerHTML);
        printHtml.document.write('</body></html>');
    
        printHtml.document.close(); 
        printHtml.focus(); = 10*/
    
        printHtml.print();
        printHtml.close();
    
        return true;
    
      }
Zubayer Bin Ayub
  • 310
  • 3
  • 11
2

My approach - Simple CSS and JS. Works on React/NextJS too.

  const handlePrint = e => {
    e.preventDefault();
    const bodyElement = document.getElementsByTagName('body')[0];

    bodyElement.classList.add('printing');
    window.print();
    bodyElement.classList.remove('printing');
  };

.printing {
  visibility:hidden;
}

.printView {
  visibility:visible;
}

.printing .printView {
  /* You can have any CSS here to make the view better on print */
  position:absolute;
  top:0;
}

What it does?

  1. Adds .printing class to body element. With CSS we hide all body content with visibility:hidden;
  2. At the same time, we keep CSS ready with .printing .printView to have any kind of view we want for the print area.
  3. Trigger window.print();
  4. Remove .printing class from the body element when the user cancels / prints.

Example:


<button onclick="handlePrint">
    Download PDF
</button>

<div>
    <h1>Don't print this</h1>

    <div class="printView">Print this</div>
</div>

Let me know if this helps anyone :)

Tejas
  • 163
  • 2
  • 8
1

The printDiv() function came out a few times, but in that case, you loose all your binding elements and input values. So, my solution is to create a div for everything called "body_allin" and another one outside the first one called "body_print".

Then you call this function:

function printDiv(divName){

    var printContents = document.getElementById(divName).innerHTML;

    document.getElementById("body_print").innerHTML = printContents;

    document.getElementById("body_allin").style.display = "none";
    document.getElementById("body_print").style.display = "";

    window.print();

    document.getElementById("body_print").innerHTML = "";
    document.getElementById("body_allin").style.display = "";
    document.getElementById("body_print").style.display = "none";

}
pmrotule
  • 9,065
  • 4
  • 50
  • 58
  • This line could be useful if you want unique id: printContents = printContents.replace(/id=("|')(.*?)("|')/g, 'id=$1$2_2$3'); – pmrotule Feb 27 '14 at 18:30
1

With CSS 3 you could use the following:

body *:not(#printarea) {
    display: none;
}
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • Can't use that I'm afraid... (correct me if wrong) the page I'm working on is asp.net 1.1 / DHTML – noesgard Jan 22 '09 at 12:18
  • It depends on the browser whether the :not() selector is already available or not. – Gumbo Jan 22 '09 at 12:21
  • Well then is my proposal just a look into the future … No, seriously. I just mentioned it for the sake of completeness. I know that it’s not practicable right now. Unfortunately. – Gumbo Jan 22 '09 at 12:26
  • You could use jQuery and this selector which (I think) would work in IE6 - $('body *:not(#printarea)').style('display', 'none'); – David Heggie Jan 22 '09 at 14:28
  • 3
    this will hide all descendants of #printarea, since they are matched by *:not(#printarea). So basicly you end up with an empty container. – cytofu Jun 10 '15 at 22:38
1

I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or JavaScript bindings. I found a perfect and easy solution that neither losses CSS nor JavaScript bindings.

HTML:

<div id='printarea'>
    <p>This is a sample text for printing purpose.</p>
    <input type='button' id='btn' value='Print' onclick='printFunc();'>
</div>
<p>Do not print.</p>

Javascript:

function printFunc() {
    var divToPrint = document.getElementById('printarea');
    var htmlToPrint = '' +
        '<style type="text/css">' +
        'table th, table td {' +
        'border:1px solid #000;' +
        'padding;0.5em;' +
        '}' +
        '</style>';
    htmlToPrint += divToPrint.outerHTML;
    newWin = window.open("");
    newWin.document.write("<h3 align='center'>Print Page</h3>");
    newWin.document.write(htmlToPrint);
    newWin.print();
    newWin.close();
    }
Zaheerabbas
  • 1,119
  • 20
  • 46
BibanCS
  • 309
  • 3
  • 9
  • This opening and creation of another window that does not work on Android. Only direct window.print() works. – Merv Jan 14 '19 at 03:10
1

Best css to fit space empty height:

@media print {
  body * {
    visibility: hidden;
    height:0;
  }
  #section-to-print, #section-to-print * {
    visibility: visible;
    height:auto;
  }
  #section-to-print {
    position: absolute;
    left: 0;
    top: 0;
  }
}
TRI ÂN
  • 59
  • 7
1

I'm very late to this party, but I'd like to pitch in with yet another approach. 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
1

I found the solution.

@media print {
    .print-area {
        background-color: white;
        height: 100%;
        width: auto;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        z-index:1500;
        visibility: visible;
    }
    @page{
        size: portrait;
        margin: 1cm;
    }
/*IF print-area parent element is position:absolute*/
    .ui-dialog,
    .ui-dialog .ui-dialog-content{
        position:unset !important;
        visibility: hidden;
    }
}
user2573099
  • 63
  • 1
  • 6
1

I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or doesn't work in all browsers. I found a perfect and easy solution that neither losses CSS and work perfectly for all browsers.

Html

<div class="row" id="print-div">
      Your html 
    </div>

TYPESCRIPT

let popupWin = window.open('', '_blank', 'width=1080,height=595');
let printContents = document.getElementById("print-div").innerHTML;
let printHead = document.head.innerHTML;
popupWin.document
    .write(`<html>
     ${printHead}
    <body onload="window.print();">${printContents}</body></html>`);
popupWin.document.close();
0

You can use this: http://vikku.info/codesnippets/javascript/print-div-content-print-only-the-content-of-an-html-element-and-not-the-whole-document/

Or use visibility:visible and visibility:hidden css property together with @media print{}

'display:none' will hide all nested 'display:block'. That is not solution.

0xC0DEGURU
  • 1,432
  • 1
  • 18
  • 39
0

I had multiple images each with a button and needed to click on a button to print each div with an image. This solution works if I have disabled cache in my browser, and the image size doesn't change in Chrome:

        function printDiv(divName) {

        var printContents = document.getElementById(divName).innerHTML;
        w = window.open();

        w.document.write(printContents);
        w.document.write('<scr' + 'ipt type="text/javascript">' + 'window.onload = function() { window.print(); window.close(); };' + '</sc' + 'ript>');

        w.document.close(); // necessary for IE >= 10
        w.focus(); // necessary for IE >= 10

        return true;
    }

<div id="printableArea">
      <h1>Print me</h1>
</div>

<input type="button" onclick="printDiv('printableArea')" value="print a div!" />
live-love
  • 48,840
  • 22
  • 240
  • 204
0

Use a special Stylesheet for printing

<link rel="stylesheet" href="print.css" type="text/css" media="print" />

and then add a class i.e. "noprint" to every tag which's content you don't want to print.

In the CSS use

.noprint {
  display: none;
}
Xn0vv3r
  • 17,766
  • 13
  • 58
  • 65
0

If you only want to print this div, you must use the instruction:

@media print{
    *{display:none;}
    #mydiv{display:block;}
}
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
0

Try this:

function printElement($elem){
    var $customPrintSection = document.getElementById('customPrintSection'),
        $customPrintSectionCss = document.getElementById('customPrintSectionCss');

    if ($customPrintSection){
        $customPrintSection.remove();
    }

    if ($customPrintSectionCss){
        $customPrintSectionCss.remove();
    }

    $customPrintSection = document.createElement('div');
    $customPrintSection.id = 'customPrintSection';

    $customPrintSectionCss = document.createElement('style');
    $customPrintSectionCss.id = 'customPrintSectionCss';

    document.body.appendChild($customPrintSection);
    document.body.appendChild($customPrintSectionCss);

    $customPrintSection.innerHTML = $elem.innerHTML;
    $customPrintSectionCss.innerHTML = '@media screen { div#customPrintSection { display: none; } } @media print { body *:not(div#customPrintSection):not(div#customPrintSection *) { display: none; } div#customPrintSection a[href]:after { content: none !important; } }';

    window.print();

    $customPrintSection.remove();
    $customPrintSectionCss.remove();
}

I like this solution because it doesn't affect the whole page, like a CSS-only solution, which in one particular answer makes all body elements invisible right off the bat. So good luck printing the whole page, if needed.

And I also prefer the "display: none" approach vs. the "visibility: hidden" one, so there's no need to make the printable element an absolute one and align it top-left. But I guess that's subjective.

And finally, it really beats the new window approach.

DECEiFER
  • 11
  • 2
-1

base on @Kevin Florida answer, i made a way to avoid script on current page disable because of overwrite content. I use other file called "printScreen.php" (or .html). Wrap everything you want to print in a div "printSource". And with javascript, open a new window you created before ("printScreen.php") then grab content in "printSource" of top window.

Here is the code.

Main window :

echo "<div id='printSource'>";
//everything you want to print here
echo "</div>";

//add button or link to print
echo "<button id='btnPrint'>Print</button>";

<script>
  $("#btnPrint").click(function(){
    printDiv("printSource");
  });

  function printDiv(divName) {
   var printContents = document.getElementById(divName).innerHTML;
   var originalContents = document.body.innerHTML;
   w=window.open("printScreen.php", "_blank", "toolbar=yes,scrollbars=yes,resizable=yes,top=50,left=50,width=900,height=400");
   }
</script>

This is "printScreen.php" - other file to grab content to print

<head>
// write everything about style/script here (.css, .js)

</head>
<body id='mainBody'></body>
</html>


<script>
    //get everything you want to print from top window
    src = window.opener.document.getElementById("printSource").innerHTML;

    //paste to "mainBody"
    $("#mainBody").html(src);
    window.print();
    window.close();
</script>
QeiNui
  • 65
  • 1
  • 8