Blog (my web musings)

Find out what's interesting me, get tips, advice, and code gems that don't fit elsewhere.

Search Blog

While striving for simplicity, I think most of us, at one time or other, have adopted a 'do it with CSS' strategy when building drop-down menus. We initially hide the sub-menus with display:none; styling, and then change them to display:block; when the parent button is hovered. It feels kinder on your noodle than doing it with JavaScript, especially if you don't feel confident in that aspect of web development. But what about web users who don't use a mouse? Is this method kind for keyboard users who tab their way around a website? Not very.

The Problem

The problem with the none-JS approach is that :hover activated CSS menus can only have their first-level buttons tabbed-to. While sub-menus can be momentarily revealed when the parent receives :focus, they will be hidden again once the user tabs off the parent button (when it loses focus). This means that a keyboard user has no way of using a CSS-only menu effectively, and if other suitable measures are not put in place (a convenient 'skip to site map' link) they'll have an almost impossible time navigating your website.

You can see the lost :focus issue in the demo below;


A Solution

JavaScript can offer a solution here using the focus event. If we add an ".active" class to buttons that have sub-menus when they receive focus, and do not remove it again until their previous or next sibling button is tabbed-to, we can attach display:block; to it in the CSS and effectively keep drop-downs visible for keyboard users while they're tabbing through child / nested list items.

Putting this theory in to practice, I've whipped up a Keyboard Accessible 'Tab-to' Menu demo;


Use your TAB key to navigate the menu (TAB moves forwards, TAB+SHIFT moves backwards).


In order for the keyboard tabbing aspect to work, first grab the JavaScript from the source of the demo, and then do the following;

  1. Include menu :focus and .active styles in your CSS for tab-to visibility
  2. Put tabindex="0" in your menu's main <ul> element - the script uses it to hide any visible sub-menus when tabbed past
  3. Use properly structured / nested lists - invalid markup screws with the script
  4. Put id="menu" in your menu's container element, or change the "#menu" selector in the script

Please note that this menu does not currently include ARIA attributes, which would further improve accessibility for screen readers. Please see Terrill Thompson's article on Accessible Dropdown Menus for more details.

In the Wild

I've already implemented this script on a few school websites that I oversee, and I've also added it to my freebie menus to improve accessibility there; Drop-Down, Fly-Out, Push/Slide.

Here's the Keyboard Accessible 'Tab-to' Menu demo again to try in your own projects;