Making accessKeys more usable
Access keys are a wonderful thing. I find myself using them all the time: Ctrl-T to open a new tab in Firefox, Alt-S to send an email in Outlook, Ctrl-S to save in editors, and of course Ctrl-C, Ctrl-X, and Ctrl-V for clipboard operations.
Now, most web pages don’t require a lot of action from the user. Most of the time all you’re doing is paging through text and following links. Where access keys really shine are pages with forms, especially if there are multiple buttons on a page, like there are in many web applications.
But wait, how useful are access keys, really, if there’s no way to tell which keys do what? Unfortunately, browsers don’t display access keys in any way (who knows why–seems like pretty basic functionality to me). So if you want your users to know of their existence, you have to tell them yourself.
You could do this by changing your button or label text to include the access key (e.g. “Submit (Alt-S)”), or you could use HTML to underline the access key in the text (e.g. <u>S</u>ubmit). I prefer the latter, since it is more concise but still consistent with the way other applications display access keys (and you don’t have to worry about the different key combinations used by different platforms and browsers–”Alt” only makes sense to Windows users). This immediately provides a clear and simple cue to the user, and goes a long way in increasing the usability of access keys.
So now the user is taken care of. But what about you, the developer? Do you really want to go through all your existing code and add extra text or markup? And what if you end up changing access keys later on, but forget to change the display? Then you’ve really created a problem for the user. Keeping redundant information in sync doesn’t sound like a hard problem, but when you’re making changes in a hurry, these things are easy to forget.
In the past, I’ve alleviated this problem by using JSP custom tags for all my input and label tags (you could do the same with PHP functions). But then you have to create a custom tag for every tag with an accessKey, and it needs to have all possible attributes for that HTML tag. It works, and it is somewhat better than doing it manually, but it just isn’t as elegant as it could be. Ideally, we should be able to use a normal HTML tag without any modification.
So, inspired by articles at A List Apart, I decided to see if I could solve the problem using Javascript. Unfortunately, we can’t put markup in input submit tags, so I couldn’t underline the access key in that case (instead I’m displaying the access key in parentheses), but for labels and button tags, it works beautifully. All you have to do in your HTML is include a script tag pointing to your javascript file.
Your HTML remains simple–all you need to do is specify an access key:
<label for="name" accesskey="n">Name:</label> <button type="submit" accesskey="s">Submit</button> <input type="submit" value="Submit" accessKey="s"/>
Here is what the javascript file looks like:
window.onload = function() {
underlineAccessKeys();
}
function underlineAccessKeys() {
var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
if (button.accessKey != "") {
button.innerHTML = underlineAccessKey(button.innerHTML,
button.accessKey);
}
}
var labels = document.getElementsByTagName("label");
for (var i = 0; i < labels.length; i++) {
var label = labels[i];
if (label.accessKey != "") {
label.innerHTML = underlineAccessKey(label.innerHTML,
label.accessKey);
}
}
var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if ((input.type == "submit" || input.type == "button")
&& input.accessKey != "") {
input.value = input.value + " (Alt-"
+ input.accessKey.toUpperCase() + ")";
}
}
}
function underlineAccessKey(string, accessKey) {
var result = "";
var foundFirstMatch = false;
for (var i = 0; i < string.length; i++) {
var c = string.charAt(i);
if (c.toLowerCase() == accessKey.toLowerCase()
&& !foundFirstMatch) {
result += "<u>" + c + "</u>";
foundFirstMatch = true;
} else {
result += c;
}
}
// if the access key doesn't appear in the text, add it to the end
if (!foundFirstMatch) {
result += " (Alt-" + accessKey.toUpperCase() + ")";
}
return result;
}
Note: I realise innerHTML is not standards-compliant, but it is widely supported, simple, and well-suited to this sort of application.
Update: I just realized that it may not be such a good idea to use innerHTML, after all. It works fine if your label or button elements contain plain text, but if they contain HTML, then my underlineAccessKey() method could end up trying to underline characters in the tag names! So, after a little more searching online, I found a page that solves this same problem, but using the DOM to manipulate text nodes. It shouldn’t be too hard to merge both pieces of code, so that it can take advantage of his DOM manipulation and of my code to handle input tags and the case where the access key doesn’t appear in the text. If I have time, I’ll post an updated version later.
August 26th, 2004 at 5:49 am
The big drawback for me with innerHTML is that it magically becomes ‘read only’ in XHTML
http://richardathome.no-ip.com/index.php?article_id=162
You end up having to write reams of DOM manipulation code achieve the same effect
And DOM scripting renders slower too
January 2nd, 2007 at 5:58 am
Hi,
This is really nice man… cool idea, but i didnt get for what u r using javascript as if we can do very simple way.
i tried like this without javascript it works…
Show generated source
January 2nd, 2007 at 6:03 am
<button accesskey="S" onclick="alert(’test’)" type="submit"><u>S</u>how
generated source</button>
January 4th, 2007 at 11:22 am
Read my 5th paragraph and I tell you why I use javascript for it.
January 5th, 2007 at 6:15 am
The tag seems to have some bad bugs in Internet Explorer as well. See e.g. http://www.google.com/search?q=ie+button+tag
Jennifer, if you do get a chance to write an updated version of your code which uses DOM manipulation and works with input tags, I for one would be very interested in it!
January 5th, 2007 at 6:17 am
Sorry, the above should have read “The *button* tag…”