Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Unobtrusive JavaScript for ‘Print-This’ Links

One of the oldest JavaScript tricks in the book involves providing a “print this!” link for visitors that enables them to summon their operating system’s default print dialogue box to facilitate quick and easy printing of whatever page they happen to be viewing. With the old way of pulling this little stunt, we write this in the markup comprising the target “print this!” link in question:

<a href="javascript:window.print()">Print This!</a>

Big yuck there, of course, due to the obtrusive nature of the JavaScript implementation. Adhering to the principles of proper Web Standards, it is better practice to separate behavior from structure by placing this amazing “print this!” function in its own location, either in the <head> element, or even better in an external JavaScript file. So basically, we want markup that looks more like this:

<a href="http://domain.tld/target/" title="Print this page">Print This!</a>

Notice the new value for the href attribute. Rather than pointing illogically to the JavaScript function, it now points to an actual resource, which may be anything you desire. Previously, users without JavaScript would click the “print this!” link and blink while nothing happens. With the unobtrusive technique, you provide the location to which users without JavaScript shall go. Possibilities here include an explanation page or even just the page itself, depending on how lazy you wanna be.

Oh yeah, the code. Removing the obtrusive JavaScript from the anchor is not enough to make this trick work. We also need a nice, unobtrusive JavaScript function to make it happen:

// unobtrusive JavaScript for "Print This!" links
// https://perishablepress.com/press/2009/02/01/unobtrusive-javascript-for-print-this-links/

function printClick() {
	if (!document.getElementById) return false;
	if (!document.getElementById("print_this")) return false;

	var link = document.getElementById("print_this");
	link.onclick = function() {
		window.print();
		return false;
	}
	link.onkeypress = link.onclick;
}

// onload function (not needed if script called at the end of the page)
// replace with "printClick();" if script called at the end of the page

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(printClick);

Nice. So what are we doing here? Well, there are two functions involved in the process. The first adds the “print this!” functionality to all target links, while the second is a generic onload-event function that triggers the “print this!” function as soon as the page has loaded. And of course, if your JavaScript file already contains this functionality, there is no need to replicate it here; simply call the printClick() function on page load.

In the first function, the first three lines apply the principle of “graceful degradation” by checking browser/device support for the three required JavaScript functions. If any of these three functions are not available, the script quietly stops, thereby preventing errors and other problems on unable devices. Then, the second two lines simply set the function variables, which together target the specific “print this!” link in the document. Finally, the function loops through all identifiable link targets and applies the desired “print this!” functionality via JavaScript’s window.print(); function.

Update: Thanks to the reminder from Tuan Anh, we have eliminated the for loop and now target the specified anchor element directly, thereby producing a lighter, cleaner and all-around better function. Thanks Tuan Anh! :)
Update: Thanks to the heroic help of Anatoli Papirovski, we may eliminate the onload() function from the script when calling it from the bottom of the document (as prescribed in the following section). If you are calling the script from the <head> section, the onload() function will need to be included. Thank you, Anatoli Papirovski! :)

To implement this technique, place the previous code into an external JavaScript file, say, “javascript.js” (so creative) and then link to the file at the bottom1 of your (X)HTML document like so:

			.
			.
			.
		</div>
		<script src="javascript.js" type="text/javascript"></script>
	</body>
</html>

Almost there.. the last thing you need to do is identify the “print this!” link by adding an id attribute of “print_this”. Place this code wherever you would like the “print this!” link to appear:

<a id="print_this" href="http://domain.tld/target/" title="Print this page">Print This!</a>

..and of course, you should also change the location of the href attribute to reflect the location that non-JavaScript users will go to upon clicking the link. For WordPress-powered sites, you may use the <?php the_permalink(); ?> template tag for the href value, thereby enabling “print this” links for every post on your site.

That’s all there is to it, really. Test that everything works and marvel in your users’ new ability to easily print your pages using this remarkable unobtrusive JavaScript technique. Ahhhh, what a feeling! ;)

Another Update!

Another useful unobtrusive “Print This!” technique. Here, we are using unobtrusive JavaScript to apply a “Print This!” button (not a link — an actual button element) next to a small bit of text that reminds people to print a copy of the page for their records. Note that the version of this method given at the Opera Dev site does not work in certain browsers due to a small error in syntax. In this version, the error has been fixed and the script should work properly in all modern web browsers.

<p id="print_this">Thank you for your order. Please print this page for your records.</p>

<script type="text/javascript">
(function printClick() {
	if (!document.getElementById("print_this")) return false;
	var link = document.getElementById("print_this");
	if(link && typeof(window.print === 'function')) {
		var button = document.createElement('input');
		button.setAttribute('type','button');
		button.setAttribute('value','Print This!');
		button.onclick = function() {
			window.print();
		};
		link.appendChild(button);
	}
})();
</script>

Footnotes

  • 1 This is the recommended location for linking to external JavaScript files according to the whole YSlow paradigm. Rest assured, however, that it is completely okay to link to the script via the document <head> as well.

About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
Banhammer: Protect your WordPress site against threats.

23 responses to “Unobtrusive JavaScript for ‘Print-This’ Links”

  1. Anatoli Papirovski 2009/02/02 9:14 am

    It does not matter if you link, you’re including the script at the bottom of your file, as such the DOM is already parsed and created. Therefore the onload element is unnecessary. If you were including the script in the head or before the element is created, you might need the onload event, but this way you don’t.

  2. Anatoli Papirovski 2009/02/02 9:19 am

    And just for fun, here’s an article on *cough* About.com *cough* talking about this basic concept: http://javascript.about.com/library/blonldom.htm

  3. I beg to differ. Test the method for yourself, both with and without the onload function. You will clearly see that the technique does not work without it. If you can prove otherwise, please do so with a working example.

  4. Anatoli Papirovski 2009/02/02 11:22 am

    I don’t know why I care about this, but here we go: http://code.fecklessmind.com/print-without-onload/

    Where’s my cookie?

  5. You care because you are so awesome! Thanks for demonstrating the onload-less method.. I see that it does in fact work, and now realize that I was forgetting to call the printClick() function after removing the onload script. You don’t get a cookie, but you do have my appreciation for taking the time to hit me over the head with this — I now have seen the light!! :)

    Edit: The article has been updated to reflect this information.

  6. @Anatoli Papirovski: Your script works well, but it’s not good for performance when we trying to load (and run) script at the end of page. Without onload function, your script will run directly at the place you put it. Of course you can put the function at the bottom, but when other scripts go to large, it will be hard to organize.

  7. Anatoli Papirovski 2009/02/03 9:40 am

    @Tuan Anh: it is very common, in fact recommended, to put JS at the bottom of your files, as it prevents delaying the loading of the rest of the page. I recommend reading “High Performance Web Sites” by Steven Souders.

  8. Jeff Starr 2009/02/03 9:50 am

    @Anatoli Papirovski: I think Tuan is pointing out the need for chronological organization of script execution, especially when precise timing is required or when numerous scripts are involved. Utilizing the onload() function is common practice, and greatly facilitates the organization and processing of scripts. Of course, for simple demo pages and other basic JavaScript implementations, using an onload() function may be overkill, as you have demonstrated.

  9. Yes, that’s what I mean. Imaging that you give your code to a newbie, they often put it in the header. Or for another example, when we hook to the WP header (sometimes), script loaded and execute there. It’s not really the best choice for us. The onload method will give us what we want – execute it at last of page, not depend on where we put.

    And of course, your script is good :), in truth, I often do that :D.

  10. Cathy Tibbles 2009/10/18 2:35 pm

    This is the first ‘print this’ post that I’ve tried that actually works with my stylesheet! Thank you. Is there a simple way to change this js to pop up an email window?

  11. Cathy Tibbles 2009/10/18 2:42 pm

    Ack. It only works on the first link. I have full posts on my front page. and I would like to have a print this link on each article. But the js craps out after the first post. Any thoughts?

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
Blackhole Pro: Trap bad bots in a virtual black hole.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.