Using tabindex for keyboard events
Up until recently, I had a fixed notion that had curiously evaded critical analysis, namely that you can only capture keyboard events – keydown, keyup and keypress – on either input elements or the document itself. I can’t put my finger on the moment I acquired this (partially true but misleading) piece of practical knowledge, but I had taken it for granted ever since.
The old way
Here’s the kind of thinking spanning from that premise: Let’s say you’re building a web app with lots of components that react to keyboard shortcuts. You’d need to attach all keydown handlers to the
document element and then figure out (and keep track of) which part of the app is “focused” so that you know what action you can take, especially when dealing with inputs vs. custom elements – hello
document.activeElement, unmaintainable code and nascent bug.
The better way
It starts with getting a better understanding of what makes a HTML element react to keyboard events. Peter-Paul Koch has an excellent overview over at Quirksmode. So it’s actually one of these:
window(if you exclude IE8 and earlier)
- a focusable element
The last one is important, because now we can ask: what are focusable elements? Clearly, inputs and links are also focusable. But could I make any element focusable? Why yes, yes you can.
tabindex is your new bicycle
You might remember
tabindex as the way to specify the order with which hyperlinks and form elements are traversed when the user presses the Tab key. But it’s also how you can specify that arbitrary elements in your markup (the
<div> elements that make up your components) are focusable and thus can capture keyboard events.
All we need to do is specify
tabindex="0" on our the outermost element of our components and we can start attaching keyboard events to it. Here’s a quick demo:
Not only does this simplify our code, but we also get a nice accessibility boost. You can read the full MDN article for more details and guidelines for using the
I, for one, have a web app to fix.