Accidental accessibility

I’ve been working on a search suggest box for a project. You know the type: you start typing in the search box, and a list of suggestions appears below it.

Disclaimer: this is the first time I’ve written about web accessibility, so be gentle. That said, I am by no means too proud to learn (thus this post), so I welcome any comments, changes, or corrections on my code.

The part I’m going to write about isn’t getting the list to show up (I’ll just assume you know how to do that, because that’s not the point of this post), but rather keyboard controls of the items within the list.

It’s a pretty common UI pattern to be able to navigate search-suggest items with the keyboard, but the initial solution I wrote wasn’t accessible at all. The focus stayed in the search input, all while changing the class (and therefore the visual aspect only) of the “keyboard-selected” list item. Pressing the enter key, while there was a “selected” item, would go to that item’s URL instead of submitting the search form.

You can see a generic version of this functionality here:

The initial problem which presented itself was not (I am ashamed to admit) accessibility, but rather the action of opening the drop-down item’s link. Some (but not all) needed to open in a new window, and using window.open() doesn’t always work.

To clarify, it’s actually not so much that it doesn’t work, but rather that it gets blocked. Browsers (with the default security settings, anyway) will block any popup that isn’t user-initiated. A popup opened within an element’s click() event, for example, is treated as user-initiated. Opening a popup from within a keypress event, not so much. (Sure, you can rely on the user to allow the popup, but that’s pretty bad UX.)

It occurred to me that pressing the enter key on a link that has focus behaves exactly the same as if it were clicked. So if a link with the target="_blank" property has focus, pressing the enter key will open it in a new window.

With this realization, I rewrote how the search box handles up and down arrow keypress events. The focus actually leaves the input field, and since <a> elements are focusable (they have to be, for accessibility reasons), the focus moves along the list of items. The focus() and blur() event, bound to each item in the list, toggles the class used to indicate visually which item is selected, as well as the aria-selected property.

In retrospect, the focus (if you’ll pardon the pun) of accessibility should have been first and foremost in writing the keyboard functionality for my input field’s dropdown. Still, I’m happier with its behavior now than I was with the first version.

Edit on 7/21:

I got the following feedback on my (what I hoped was) accessible dropdown:

while I like the idea you had and the way it’s built in that codepen is great, there is one thing you forgot:

people using the keyboard to navigate use the tab-key to move from link to link, not the up- and down-arrow-key.
Somehow you’d either need to tell sighted and non-sighted keyboard users that you changed this very common behaviour or add tabbing as a means to move through the dropdown links-list.

What I’d also advise is to get rid of the wrapping div container for the list and instead use a ul (or ol if the results are in a specific order) and wrap each link in a list-item then. That way users with a screenreader will be told that they are navigating a list, how many items are there and on which level of the list they are on.

Taking that into account, I rebuilt the list markup, making it a <ul>. I also added logic in the JavaScript that allows for tab and shift+tab behavior, updating the focus and aria-selected properties accordingly.