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> of the document 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
// http://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. Of course, if your JavaScript file already contains this functionality, there is no need to replicate it here; simply add the requisite function call accordingly to call the printClick() function upon 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 bottom 1 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!

I recently discovered another useful unobtrusive “Print This!” technique. This method was found at Opera’s Dev Site as an example of how progressive enhancement trumps graceful degradation in design. 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>

Notes

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.