Links & JavaScript Living Together in Harmony

Originally published on evolt.org

It seems there's not a week that goes by that someone isn't asking about how to properly execute some JavaScript from a link. Unfortunately, they're not usually driven to bring their problem to others for help because they're trying to make their site as usable and accessible as possible.

So what's the problem?

The most likely problem that brings them away from their troubleshooting session, and to one of the many discussion lists I subscribe to, is the document "jumping" back to the top when a link is clicked. Other times, it's the JavaScript not behaving properly or outright throwing an error.

So what's the solution?

Nearly always there are responses that tell the poster to add return false to the onclick event handler immediately after executing the JavaScript statement(s) or to put the JavaScript statement(s) in the href attribute prepended with the JavaScript: pseudo-protocol rather than use the onclick event handler at all. It's too bad that none of these solutions really addresses the larger problem — how to make the link degrade well for non-JavaScript users.

If we're trying to accommodate non-JavaScript users, why use JavaScript at all?

There are many reasons to execute JavaScript from a link. The most common uses involve navigating to other pages, opening a link in a popup window, or worse, submitting a form. All of these reasons can be addressed while not leaving out non-JavaScript users. Some of the less common reasons usually involve more complicated JavaScript-driven functionality. However, while the functionality can't likely be reproduced for non-JavaScript users, especially in the case of DHTML, the link that's used to trigger this functionality can be used to either execute server-side functionality to mimic or duplicate it or inform non-JavaScript users what they would be getting if they were using a browser with JavaScript support.

So what's really the solution?

The solution is to think about the functionality the JavaScript will provide and how to accomplish the same task without it. Get it working without first, then add JavaScript to enhance it for JavaScript enabled browsers. Let's take a look at some of the common reasons.

What's the most common reason and its solution?

Opening a link in a popup window

Generally developers will open links in a popup one of two ways:

Executing JavaScript from the onclick event handler and setting the href attribute value to "#".
<a href="#" onclick="window.open('somedoc.html', 'newWindow')">click here</a>
Executing JavaScript from the href attribute by way of the JavaScript: pseudo-protocol.
<a href="JavaScript:window.open('somedoc.html', 'newWindow')">click here</a>
Note
This second example is particularly bad because it causes the link to break for users that prefer to shift+click the link to open it in a new window, unless they're paying close attention to the address in the status bar and notice it's executing a JavaScript statement.

Before charging off thinking either of these ways is the solution, give the code above a try in your browser with JavaScript disabled. You'll notice the first example will cause your browser to jump back to the top of the document if you had to scroll at all to see the link and the second example does absolutely nothing. So, let's talk about how we're going to make this work for non-JavaScript users as well.

Just how do you open a new window for non-JavaScript users?

The beginnings of accessible popup windows is in the use of the target attribute of the <a> tag. We finish it off for non-JavaScript users by placing the link where it belongs — in the href attribute.

<a href="somedoc.html" target="newWindow">click here</a>
But what about the fancy popup for JavaScript enabled users?

To have the browser open a popup window, based on our own settings, we place the necessary JavaScript into the onclick event handler. In addition to this bit of JavaScript, we make sure to add a return false statement as the last bit to keep the browser from executing the default behavior of a link with a target -- opening a normal browser window. We eliminate the need to code the link to the document and the new window name twice by using the this keyword which makes a reference to the containing object, in this case the <a> tag. Using the this keyword and object.property notation, we can access the href attribute value and the target attribute value.

<a href="somedoc.html" target="newWindow" onclick="window.open(this.href, this.target); return false">click here</a>
Congratulations! You've made your first completely accessible popup window.

So what are some solutions to other common reasons for executing JavaScript in a link?

If you're trying to submit a form from a link, stop, go directly to jail, do not collect $200.00. Besides the numerous expected behaviors of forms that you're breaking (we're talking about usability here) by not using a submit button of some variety, you're needlessly neutering the form for non-JavaScript enabled users. In the years I've been playing this web game, I've yet to run across a valid reason for breaking a form in this fashion.

If the reason you're looking to use a link is so you have a graphical submit button, stop, go read the html spec, do not collect $200.00 — hello, this functionality is already built-in via the <input> tag with a value of image for the type attribute. If you're stuck implementing someone else's design and they insist upon rollovers on the submit buttons, there are better alternatives that don't break the form for non-JavaScript users.

What's an example of one of the less common reasons and a possible solution?

Suppose you have an application that lists a number of events. These events can be in any number of categories. Using DHTML, you want to give users with capable browsers the ability to see what events belong to which categories, on the fly, without reloading the page. What do you do about non-JavaScript browsers so they get the same end result, albeit with a reload of the page?

We start by building the application without the DHTML. We pass the information about the category the user clicked on to the application so it knows what dates on the calendar and what events in the listings below to "highlight" — this is the simpler part.

We then write a JavaScript function to change the background and foreground colors of the dates in the calendar and the individual events in the listings and change the color of the link the user clicked on to indicate which one is "selected". We call this function from the category links using the onclick event handler. Since this example uses JavaScript that not all Javascript-capable browsers understand, we make sure the function call is prefaced by the return statement. We also make sure the function returns a boolean value of true if the browser does not support the method(s) we're using so it will follow the link just like non-JavaScript capable browsers or otherwise a boolean value of false so the DHTML can be executed without the browser following the link.

The function

function selectEvents(category_id)
{
  if(!document.getElementById) return true;
  // DHTML bits go here
  return false;
}

Calling the function

<a href="/calendar/february/2002/6/1" onclick="return selectEvents(1)">Snowboarding</a>

So what do I do if it's not possible to replicate the functionality server-side?

If for some reason you can't replicate the functionality with some server-side shenanigans, then simply use the href attribute to link to a document that will explain what could be gained by using a JavaScript enabled browser. To execute the JavaScript, use the onclick event handler, remembering to add the return false statement at the very end to prevent JavaScript enabled browsers from following the link. You might also consider using the onmouseover and onmouseout event handlers to write to the status bar to mask the link to the document for non-JavaScript users to prevent confusion on the part of the JavaScript enabled user should they look at the status bar when mousing over the link. If the functionality your JavaScript statements provide is not compatible with all JavaScript enabled browsers then you may consider prefacing the function call with the return statement as in the example immediately above.

Executing JavaScript that is compatible with all JavaScript enabled browsers

<a href="js_required.html" onmouseover="window.status = 'click here'; return true;" onmouseout="window.status = '';" onclick="myFunction(); return false;">click here</a>

Executing JavaScript that is not compatible with all JavaScript enabled browsers

<a href="js_required.html" onmouseover="window.status = 'click here'; return true;" onmouseout="window.status = '';" onclick="return myFunction()">click here</a>

In conclusion

I haven't covered all the possibilities or reasons for calling JavaScript within links. However, I hope you've seen that there are ways to do so and have the page degrade as gracefully as possible. If I haven't touched upon something you've struggled with, I hope I've given enough inspiration and guidance to encourage you to find the most usable and accessible solution possible. Links and JavaScript really can live together in harmony.