Editable Accesskeys
Accesskeys are a very nice mechanism for making your website more accessible. You can define a set of keyboard shortcuts for common navigational tasks, making it easier for visitors, who can’t (or don’t wish to) use a mouse, to find their way around your site. For instance, on this site, hitting Alt -4 (Cntrl -4 on a Mac) takes you to the search form on the current page; Alt -1 (Cntrl -1) takes you to the main page of this blog, etc.
Unfortunately, accesskeys suffer from two big drawbacks
- There’s no easy way for visitors to discover what accesskeys are defined on a particular site.
- The accesskeys you define may conflict with the user’s existing keyboard shortcuts. Even if they don’t, accesskey assignments vary from site to site, so there’s no “muscle memory” advantage to them.
The first problem is easy to fix. Long ago, I put a listing of the accesskeys, defined here, in the footer of each page. Scroll down to take a look at it. The markup that generated the footer is
<div id="footer"> <h2>Access Keys:</h2>
<dl id="AccessKeyList"> <dt>0</dt><dd><a href="/~distler/blog/accessibility.html" accesskey="0">Accessibility Statement</a></dd> <dt>1</dt><dd>Main Page</dd> <dt>2</dt><dd>Skip to Content</dd> <dt>3</dt><dd>List of Posts</dd> <dt>4</dt><dd>Search</dd> <dt>p</dt><dd>Previous (individual/monthly archive page)</dd> <dt>n</dt><dd>Next (individual/monthly archive page)</dd> </dl>
<a href="/~distler/blog/archives.html" accesskey="3"></a> </div>
and it can be included at the bottom of every page, using SSI, PHP or, in my case MovableType’s <MTInclude>
directive. Of course, this definition-list didn’t have to be in the footer of the page. It could have been in a CSS drop-down menu at the top of the page or … The point is to make it unobtrusive, and yet easily-discoverable. Someone, with better design skills than I, could have found a more artful solution.
The second drawback seemed harder to surmount. Somehow, we need to let the user customize the accesskey assignments. But how?
Recently, Gez Lemon found a solution using server-side scripting. Unfortunately, it was more than a little cumbersome. As a web-author, it requires mucking with the markup of your pages1. As a user, it involves thoroughly unnecessary back-and-forth interaction with the server. Still, it was inspirational. Once you realize it can be done, you start to think about other ways to achieve the same effect.
I wanted something that would not involve mucking with the existing markup of my pages, and which would work client-side (so as to be as fast and smooth as possible). If you’ve read this far, you probably want to see it in action. Scroll down2 to the bottom of the page and hit the, hitherto mysterious, button. You can assign any keyboard character you want to an accesskey, though most browsers do not distinguish between uppercase and lowercase letters. If you want to disable one (or all) of the accesskeys, simply delete the corresponding character. When you’re happy, hit . You can now use your new accesskey assignments anywhere on this blog. And they’ve been saved in a cookie, for your future surfing pleasure. If, instead, the current accesskey assignments suit you, just hit .
No markup was butchered to achieve this effect. All I needed to do was include this Javascript file and add initializeAccessKeys();
to the onload
-handler for my pages. In fact, the Javascript uses the existing markup (a definition-list whose id="AccessKeyList"
)3 as an editing template for customizing the accesskeys.
I rather enjoyed crafting this, my first somewhat nontrivial bit of Javascript programming. There’s something delightfully recursive about using DOM-scripting to add event-handler attributes which, when activated, trigger other DOM-scripting operations.
I’ve only tested it in a few browsers (Mozilla, Safari and Opera), but expect it to work in others as well. Suggestions for improvements are welcome.
Update (1/16/2006):
Gez Lemon has crafted a Greasemonkey script to obtain similar (but not quite as good) functionality on any website with accesskeys. I’ve written a followup post about it. I’ve also revised my Javascript to play more nicely with Gez’s script.Update (4/2/2006):
Rich Pedley wins the prize for catching a bug in the previous version of this Javascript. I’ve updated it to fix the bug.Postscript: Event Handlers
Getting keyboard navigation to work right in the presence of certain event-handlers seems to be a black art. All the sources I’ve looked at give incorrect advice. As a consequence, I, myself, have been doing it wrong for years now.
onclick="..."
by itself doesn’t work right. The user should be able to trigger this handler by hitting Return. But that doesn’t happen in Safari (and, perhaps, other browsers).
onclick="..." onkeypress="..."
will cause the handler to be triggered by hitting any key. Which is not what you want: that breaks Tab-navigation. What does work is
onclick="..." onkeypress="if(window.event.keyCode == 13){...; return false;}"
Since I haven’t seen this explained anywhere4, I figured I’d spell it out here, and save someone else from tearing their hair out, too.
1 Among other drawbacks, Gez’s implementation is limited to the creation of <a href="" accesskey="">
and <label for="" accesskey="">
elements. No other attributes are allowed, and you can’t use it with <area>
, <button>
, <input>
, <legend>
or <textarea>
, all of which are permitted to carry accesskey attributes.
2 You can also use keyboard navigation: hit Shift -Tab, to move to the bottom of the page, highlighting the button. You should be able to hit return to activate editing of the accesskeys for this site (you can navigate between the editing field using Tab and Shift -Tab).
3 The script assumes a <dl id="AccessKeyList">
. If you want to give the definition-list containing the accesskeys and their meanings a different id
, change the value of the accesskeylistid
variable in the script.
4 Peter-Paul Koch’s otherwise-excellent table of Javascript Event support is, I’m afraid, incorrect on the status of onclick
support in Safari.
Re: Editable Accesskeys
Very interesting, the edit/save function is a nice feature. But is DOM scripting the right approach when it comes to Accessibility?
For this solution to degrade nicely, I think no accesskeys should be set by default, so if the script fails, the user is not stuck with your own values.
For people interested in Server-Side solutions, this is another approach.