Accessible Dropdown Menus

This blog post is old. For a more recent update on this topic, see Accessible Dropdown Menus Revisited.

A couple weeks ago at the 27th Annual CSUN International Technology and Persons with Disabilities Conference I gave a presentation on accessible dropdown menus. In that presentation, I walked through several examples of accessible menu techniques (and a few not-so-accessible ones). All the examples are available on my Dropdown Menus Test Page.

Screen shot of a dropdown menu with top-level menu items About, Academics, Admissions, and Visitors; the Academics dropdown menu is open and visible

Dropdown and flyout menus on websites are great for reducing clutter, simplifying page content, and providing a consistent navigation structure that (if done well) makes it easy to find content from anywhere on the site. Unfortunately, very few of the dynamic menus in use today are fully accessible:

  • Most dynamic menus depend on users being able to use a mouse. Mousers hover over menu items, which makes dropdown menus appear. If non-mousers tab to those same top-level menu items, they typically can’t make the dropdown menus appear.
  • Most dynamic menus depend on users being able to see. Dropdown menus are typically hidden with display:none in CSS, and revealed by changing that to display:block using JavaScript (triggered, as noted above, by a hover event). If screen reader users can somehow trigger the change from hidden to visible, that change is not likely to be communicated to them, so even if the dropdown menu is visible it isn’t necessarily accessible.

The quest for an accessible dynamic menu started as early as 2003, when Patrick Griffiths and Dan Webb published an article on A List Apart titled Suckerfish Dropdowns, proposing a menu system that was structured in HTML using a very simple nested unordered list, with a small amount of CSS and JavaScript that made it look and behave like a menu. However, as proposed this didn’t work for keyboard users nor screen reader users, but the stage was set for subsequent efforts (e.g., Son of Suckerfish, Superfish, and several others) that improved accessibility.

Many of these early models are still in use today. Most dynamic menus on the web are structured using standard HTML. A few of these menus position the sub-menus off-screen rather than hiding them with display:none, which means they’re accessible to screen reader users at all times, even though sighted users can’t see them. These menus aren’t perfect—they’re just lists of links, not interactive menus. But technically they’re accessible.

The bigger problem is for sighted non-mousers, who may be navigating the web page with keyboard only, typically using the tab key. When menus are positioned off-screen, they may or may not be re-positioned on-screen when a keyboard user tabs to their parent top-level menu item. Consequently, users can tab through the items in the drop-down menu, but they can’t see them. It’s pretty silly.

Some menus today do actually become visible when they receive keyboard focus, which solves the problem described in the previous paragraph and would seem at first glance to be fully accessible. However, even these menus aren’t very usable because users have to tab and tab and tab and tab, on and on to get through the menus. If there are many items in the menus and submenus, it can take forever to get to the third or fourth top-level menu item.

The Solution Part 1: ARIA

The W3C’s draft specification for Accessible Rich Internet Applications (ARIA) makes it possible to supplement HTML with attributes that explicitly communicate the roles, states, and properties of the various parts that make up a menu system. As assistive technology (AT) users interact with the menu, ARIA passes updated information to their AT, and their AT then communicates that information in meaningful ways.

A dynamic menu system might include the following ARIA markup:

  • role=”menubar” on the menubar’s root element, typically a <ul>.
  • role=”menu” on the root element for each of the dropdown menus, which typically are either coded as <ul> or <div>.
  • role=”menuitem” on each actionable item in the menu system, including those on the menubar and those in drop-down menus and sub-menus
  • aria-haspopup=”true” on any item that triggers the display of a dropdown menu. This is typically applied to all top-level menubar items, and to any menu items that have sub-menus.
  • aria-hidden=”true” on each dropdown menu’s container element, typically either a <ul> or <div>. When JavaScript is used to make the menu visible, it should also change this attribute to aria-hidden=”false”.

Putting this all together, an accessible ARIA-enhanced menu would look something like this:

<div role="navigation" aria-label="Main menu">
  <ul id="nav" role="menubar">
    <li role="menuitem" tabindex="0" aria-haspopup="true">
      <ul role="menu" aria-hidden="true">
        <li role="menuitem" tabindex="-1">
         <a href="#">News</a>
        <li role="menuitem" tabindex="-1">
         <a href="#">Contact Us</a>
    <li role="menuitem" tabindex="0" aria-haspopup="true">
      <ul role="menu" aria-hidden="true">
        <li role="menuitem" tabindex="-1">
         <a href="#">Degree Programs</a>
        <li role="menuitem" tabindex="-1">
         <a href="#">Faculty</a>

This is the future of menu system. On my Dropdown Menus Test Page, there are three examples that apply markup similar to this, and the rest of this blog post I’ll be comparing them. They are:

  1. Simply Accessible CSS Dropdown Menu, an example menu created by Derek Featherstone
  2. YUI Library MenuNavNode Plugin
  3. Open Ajax Alliance (OAA) Menubar, with some customizations.

These three example menu systems are all similar, but differ slightly in how they’re implemented. The Simply Accessible menu is the cleanest of the three, consisting purely of <ul>, <li>, and <a> elements, with a single class=”nav” applied to the root <ul>. All the ARIA markup is added using JavaScript. YUI takes a similar approach (adds the ARIA markup using JavaScript) but there are very specific instructions that must be followed when coding the HTML, including specific class names that need to be added to nearly every element. The OAA menu differs from the others in that it starts with the ARIA markup already included in the HTML.

These three example menus differ in other ways too. Please read on!

The Solution Part 2: A Robust Keyboard Model

The WAI-ARIA 1.0 Authoring Practices site includes a standard set of Design Patterns, adopted from the DHTML Style Guide. These design patterns were developed by a group of key stakeholders to define a set of recommended models for how web-based menus and other interactive widgets should behave. In a nutshell, users should be able to tab into the menu, but once the menu has focus, they should be able to navigate left, right, up, and down using the arrow keys. Pressing enter, space, or down arrow on a top-level menu item should trigger the display of the dropdown or flyout menu if one is present, and pressing escape should close it and return focus to the parent menu item. When users tab out of the menu, any open sub-menus should close.

Each of the three example menus implements most of these recommendations. One recommendation that is not currently implemented by YUI, but is implemented by the other two, is support for jumping to a menu item by typing the letter that item starts with. This is a very cool feature, and saves users a lot of keystrokes especially if the menu is large.

Despite the similarities in the example menus, there is one important difference in their keyboard models: How they handle the tab key.

The Tab Key in Dynamic Menus

The DHTML Style Guide says this about the Tab key:

First item in menu bar should be in the tab order (tabindex=0).

The Style Guide does not expressly forbid other items in the menu being in the tab order, and each of the three menus supports tab differently.

In the Simply Accessible menu, every menu item is included in the tab order, including all the sub-menu items. This behaves just like the “accessible” menus of yesteryear. Everything’s technically accessible, but it’s not very usable since it requires so much tabbing. The difference in this case though is that users don’t have to tab. They can navigate more efficiently with enter, space, arrow keys and escape. But how will users know that? That’s the way keyboard-accessible menus in software applications have always behaved, but historically web-based menus haven’t had this functionality. This menu system works using the old method, so if users don’t know about the new method they can still access the menu items.

In contrast, the YUI menu has only one tab stop. The very first menu item has tabindex=”0″, so users tab to that within the normal tab order of the web page. However, if they hit tab a second time they exit the menu. The only way to navigate within the menu is to use the new, more efficient navigation keys.

The Customized OAA menu provides a middle path between these two extremes. Each of the top-level menu items has tabindex=”0″, so users can access each of these items within the tab order, but to access dropdown menus they’ll have to use other keys. Users probably won’t even know there are dropdown menus until they press Enter, which they would normally do anyway, expecting that to take them to another web page. In this case, pressing Enter doesn’t lead to a new web page, but triggers the display of the dropdown menu.
At this point the old model (tab) doesn’t take them into the dropdown menu, so there might be some initial confusion, but most users will probably guess a down arrow might work, and it will.

Which model is best?

This would make for an interesting research project. Assemble a large sample of users who typically navigate without a mouse, randomly assign them to one of three groups, and watch them interact with one of the three menus. Which group would learn the new keyboard model first? My hunch is that it would be the OAA group. The YUI group would be forced to learn – there’s no other way to navigate. However, in a sink-or-swim situation I think some users may give up and sink (I’m flashing back to experiments on “learned helplessness” that I did with rats as an undergrad). The Simply Accessible menu users have no reason to change. What they’ve always done works, and they’ll just use that method without realizing there’s a better way. So… I like the middle path of the OAA menu. Users are gently introduced to the new way, but their survival doesn’t depend on their mastering it.

What role for the menu root? menubar vs. menu vs. navigation

I’ve been using role=”menubar” for horizontal web-based menus such as those at the top of most web pages. The Simply Accessible and OAA menus both do the same, although the original OAA menubar example, prior to my customizing it, was used in a slightly different context than for website navigation. In contrast, YUI uses role=”menu”.

In the ARIA spec, menubar is defined as “A presentation of menu that usually remains visible and is usually presented horizontally”. There’s some supplemental explanatory text accompanying that definition, none of which dissuades me from using this role. However, I’ve been challenged by a couple of folks since CSUN, both suggesting that role=”menubar” was intended for menus in web-based applications such as Google Docs, which are fundamentally different than other web menus in that they consist of functions, rather than navigation links. But that difference isn’t explicitly required by the spec, so I still think menubar is the best fit. I personally like it better than role=”menu” since each dropdown menu within the larger menu system is marked up with role=”menu”, and the overall parent widget is a fundamentally different sort of object than the dropdown menus, so it seems fitting to assign them different roles.

The bottom line: Both role=”menubar” and role=”menu” seem to work for screen readers (see the details below). They identify the widget as a menu, identify sub-menus as sub-menus, and in some cases provide additional instructions.

One problem though is that neither menubar nor menu is a landmark role. There are only eight landmark roles (application, banner, complementary, contentinfo, form, main, search, and navigation), and all screen readers recognize them and provide a means for users to jump quickly to those regions. The most relevant landmark role for a navigation menu is role=”navigation”. However, the root element on our menu is role=”menubar” or role=”menu”, and only one role is permissible per HTML element. If we were to try adding role=”navigation” to the root element in the HTML of either the Simply Accessible or YUI menus, that role will be overwritten with role=”menubar” when the page is loaded. Even if we were able to pull that off, it wouldn’t be valid since the menu also includes items with role=”menuitem”, which require an ancestor with role=”menu” or role=”menubar”.

So, the workaround I’m using is wrapping the entire menu in a container <div> with role=”navigation”.

Screen Reader Support

Screen reader users might choose to navigate to the menu using their screen reader’s landmark shortcut key (e.g., semicolon in JAWS, the letter “D” in NVDA). When they do so, their screen reader will announce “Navigation Region”, along with a name of the landmark if one is assigned (e.g., using aria-label). On each of my example menus, I’ve added aria-label=”Main Menu”, so JAWS (for example) announces “Main Menu Navigation Region”.

From here, users will draw from their knowledge or experience in deciding what to do next. They might press down arrow to enter the menu, or they might press tab. Either way, I would expect their screen reader to announce that they’ve arrived on a menubar or menu, and to provide some meta data about that menubar, such the number of top-level items it contains. JAWS currently provides a more user-friendly experience than either NVDA or VoiceOver, although I only tested the latter in OS X Snow Leopard – I haven’t upgraded to Lion yet. In JAWS, when a top-level menu item has focus, JAWS announces the name of that menu item, and announces that it has a submenu. It also says “To move through items press the up or down arrow”. It only does this once per menubar widget, assuming it doesn’t need to repeat itself with such a simple instruction. Overall, the interaction with the menu using JAWS is easy and intuitive, at least that’s true of the YUI and custom OAA menu. Curiously, JAWS doesn’t recognize the Simply Accessible Menu as a menu. Users can navigate through this menu with the tab key, and JAWS announces all the menu items as links. However, if users attempt to use the menu’s supported keystrokes, it just doesn’t work. Since the Simply Accessible Menu is coded very similarly to the others, I think these are probably just bugs rather than problems in design philosophy. The takeaway: Whichever menu you choose to implement, be sure to test carefully using mouse, keyboard, and if possible, multiple screen readers.

What about Mega Menus?

Mega Menus are ultimately the problem I’m seeking to address. Today’s dropdown menus often contain more than just lists of links—they might contain all sorts of structured content, including headings, paragraphs, images, videos, and more. Do the menu methods described in this blog post apply to mega menus, or is some alternative model required? I’ll tackle that in my next blog post. Stay tuned…

13 replies on “Accessible Dropdown Menus”

Thanks for the great work and explanation. I know a little html and CSS but haven’t created a real site. Problem is, my employer and my friend’s small business both use Joomla to create their sites. Can the Joomla defaults for creating menus be replaced with something like this? I am just learning, so please excuse an ignorant question.
BTW, I notice that on this and other sites, it is necessary with Window-eyes to tab past form fields then tab back before the label is spoken. I assume this is a bug in WE.

Hi @Lisa, a lot of websites these days use content management systems such as Joomla, Drupal, and others, and add features such as menus to their sites by plugging in extensions or modules that are available for that CMS. It’s important for anyone who knows and/or cares about accessibility to help advocate for accessibility in those extensions and modules by reaching out to their developers or contributing time to developing an accessible alternative. If accessible options are widely available, this will have a positive impact on the accessibility of huge numbers of websites, which is better than creating a custom solution for one website. That said, I’m not sure what’s currently happening with Joomla extensions – there may or may not already be an accessible menu extension available. But if not, it’s important to have that conversation within the Joomla community.

As for Window-Eyes not announcing form labels on the first pass, that may indeed by a Window-Eyes bug. I don’t have Window-Eyes, but there’s nothing unusual about the coding of the form fields on this blog, and JAWS and NVDA announce them as expected.

Joomla has made a commitment to accessibility. They have shipped with an accessible frontend template for years and with an accessible backend template for the past year and a half.
Whether or not the menu on a particular Joomla website is accessible depends on the template you choose (or on the menu menu module you install if you don’t use the default one.) Usually developers who put the effort into making their extensions accessible will mention it in their descriptions.

You have your history a little wrong ­čÖé

The first list-based flyout menu was published by Eric Meyer in 2002, but it’s use of CSS :hover made it inaccessible to keyboard users or to older browsers. Soon after that a menu was published at which supplemented the structure with simple JS so it worked in IE.

Suckerfish came after that. It didn’t improve anything in terms of accessibility, but it was far more attractive and appealing to designers. Because of that, and its publication at ALA, it became much more well-known that any of predecessors, and that’s why most people mis-credit it as the first.

But the first proper accessible dynamic menu was UDM4, published right at the start of 2004, which was also a list-based structure styled with CSS, and had full keyboard navigation via tab and arrow-keys, menu close-timers and self-repositioning to make it decently usable. It was also the first menu (in fact, afaik, the first anything) to implement what are now known as “structural labels” — inner headings which provide a degree of random-access to ATs using their headings-reading mode.

A follow-up both for your list of accessible sites and this one — I went hunting for accessible mega-menus and found this:

It’s incredibly impressive to see concurrent development both of old and new themes to ensure each is accessible and furthermore, share such work back with the wider community:

That said, their own site is a bit poorly constructed. I finally landed on the Web Experience Toolkit homepage to discover that they had moved development to Github (yay!) at and sure enough, the last update was 8 hours ago, so forking might be a good approach if using their HTML as a template. I wonder if any other governments are doing this, and if we will ever see an accessible Twitter Bootstrap/Boilerplate turn up, though we’ll only be halfway there at that point. (Kind of like usability testing, I suppose. Some people forget everyone else exists.)

To update the above example/demo link, here’s the latest one hosted on Github:

tabbing through the menus: is this functionality browser specific? Worked for me on Chrome but not firefox.

Great write up! I decided to go with **Derek Featherstone’s** menu. One small issue though is that on hover the drop down’s stay in view unless you hover over another top level menu item or **click** anywhere outside of the drop down. The drop down should disappear once hovered out of the drop down. This is happening because of the `menuHoverClass` being applied i.e. it’s not being removed once hovered out of the main menu. I couldn’t easily figure out how to fix it. You don’t actually need the `menuHoverClass` to be applied for **hover** as it can be handled with pure CSS e.g. `.nav-main li:hover ul`. If I’m not mistaken the only thing needed to be done within the hover function: `$(top_level_links).hover(function(){});` is applying the correct value for `aria-hidden` on the drop down menu’s?

Also with the **OAA** menu it doesn’t really support top level menu items being links which is quite common in some main navigation set-ups.

Also another challenge is when you’re doing responsive sites. All the ARIA attr’s wouldn’t be required when you might change the menu layout on small screens (smart phones) as you might have the entire menu visible in a linear fashion which is hidden/shown via a **Menu** toggle button (which would require it’s own set of ARIA attr’s). You’d have to do some JS detection of the viewport size and only apply the menu JS for viewports above a certain size i.e. non-smart phone. Then there’s the issue of making the drop down menu’s touch compatible for larger screens than phones e.g. tablets.

Me again. After spending a fair few hours implementing the **OAA** and **Simply Accessible** menu’s I found a few shortcomings/bugs:

**Simply Accessible**
– Top level links can’t be followed with the keyboard i.e. hitting ENTER/SPACE keys will not follow the link as these keys are being used to open/close the drop down which is needed but so is following the link. I’d say this is a significant issue for keyboard users as all links need to be accessible.
– `aria-hidden` attr value on drop downs doesn’t update properly for `hover()`, it mostly works when you’re hovering within the menu but when you hover out of the menu the last drop down to be opened will still have `aria-hidden=”false”` even though it’s no longer visible.
– The right arrow key isn’t doing the same behaviour as the left arrow key when in drop downs i.e. when in a drop down menu the left arrow key will take you out of the drop down and to the top level menu item that comes before the drop down menu you’re just in.

This was my favourite but I had to go back to the **Simply Accessible** menu as it’s just not flexible enough i.e. you can’t have top level menu items has links or a top level menu item with no drop down as the keyboard interaction no longer works properly. So it’s expecting every top level menu item to have a drop down and none of those top level menu items to be links. This is too limiting for a main website navigation, it might work for some but I don’t have time to be having different variations ready, I just want a robust menu I can keep reusing.

Comments are closed.