Once upon a time, there was an element called <menu>. An element which had great aspirations. As an example, it wanted to allow developers to create interactive menus, much like those found in desktop applications. But that’s not all. It also wanted to allow developers to modify a browser’s OS-level context menus, injecting custom menu items for users to discover… and of course, to be delighted by.

After all, the end goal is always user delight.

But little did <menu> know its ambitions would only be partially realized, briefly, in a single browser engine. What splendor it could have relished in. But, the harsh reality is that in the story of HTML’s evolution <menu> is unfortunately an example of one of its pratfalls.

Where do you come from, where do you go?

From the HTML 3.2 Reference Specification (1997), in reference to the <dir> and <menu> elements:

These elements have been part of HTML from the early days. They are intended for unordered lists similar to UL elements. User agents are recommended to render… MENU elements as single column menu lists. In practice, Mosaic and most other user agents have ignored this advice and instead render DIR and MENU in an identical way to UL elements.

Note: those “early days” can be further traced back to HTML 2.0 - where in the change log (1994) <menu> is marked as being “no longer obsolete”. So, there’s some foreshadowing for you. And you can go even further back to HTML Tags, published in 1992 to read the original description for the menu element.

By HTML 3.2, “lists” had quite a section going for themselves, with <ul>, <ol>, <dl>, <dir>, and again, <menu>. However, if giving a good read to the quoted text from 3.2, in reality there were three <ul> elements (<ul>, <dir> and <menu>), and then the <ol> and <dl> elements.

HTML 4(.01) deprecated <dir> and <menu> (again). Which made sense. Why keep elements around that no one wanted to implement as specified, and thus, in reality were useless to developers? (steady now <hgroup>, we’re not talking about you today…)

And there you have it. That was the end of the <menu> el… oh… wait no.

HTML5 reintroduced <menu>, and gave it some new friends: <menuitem>, and <button type=menu>.

Time to try to start this story anew.

Once upon a time, there was an idea that developers should be able to make context menus with HTML. The <menu> element was (re)minted and it had some really interesting potential.

Or, at least, so one browser thought.

If you take a peak at the <menu> element on MDN (wayback machine link) you’ll see that Firefox had placed some bets on the horse named “menu”. Unfortunately…

Note: In previous version of the HTML specification, the <menu> element had an additional use case as a context menu. This functionality is now considered obsolete, and has been removed from the specification. Firefox was the only browser to implement this functionality…

But before we get into that, let’s rewind again – <menuitem> and <button type=menu> were all along for the ride, ready to enable developers to add their own options to right-click context menus, and such-of-the-sort. The ARIA role=menu, menuitem and its related radios and checkboxes referenced these elements as related concepts. (if you look at the ARIA 1.1 definition for menuitem you’ll notice it references HTML 5.1’s <menuitem> element as a related concept.) These ARIA roles can instead be used to allow developers to create “menu-like” components which are most definitely not standard website navigation patterns.

Seriously. Not for standard website navigation. If you feel like I’m speaking directly to you right now, I probably am. Stop it.

Firefox was alone in their work on the <menu> element. And, while browsers cannot talk, I at least imagine the other “browsers” gave the twice removed, but now reemerged <menu> element a look-see, and were like “yeah… but, no? We’re good… thanks anyway.”

Cool.

With only one browser considering to implement the element, the HTML specification (the W3C one) was also like “yeah… but, no” and made the element and its ilk obsolete in HTML 5.2 (wayback machine link). The HTML Living Standard (the WHATWG one, and the sole HTML specification since 2019) held out a bit, trying to salvage the element, or at least not completely yanking away a few of its related features. But eventually, the WHATWG HTML spec was like “yeah, but… what if it was just a type of list instead?”

Brilliant.

We’ve come full circle.

This is how we went from a definition for the <menu> element that read like:

User agents are recommended to render… MENU elements as single column menu lists. In practice, Mosaic and most other user agents have ignored this advice and instead render DIR and MENU in an identical way to UL elements.

HTML 3.2 Reference Specification

to

The HTML <menu> element represents a group of commands that a user can perform or activate. This includes both list menus, which might appear across the top of a screen, as well as context menus, such as those that might appear underneath a button after it has been clicked.

The <menu> element on MDN

to

The menu element represents a toolbar consisting of its contents, in the form of an unordered list of items (represented by li elements), each of which represents a command that the user can perform or activate. NOTE: The menu element is simply a semantic alternative to ul to express an unordered list of commands (a “toolbar”).

— The <menu> element as defined in the HTML specification.

So there you have it. The <menu> element. A way to semantically identify a list of… wait. What’s that? It’s not even consistently exposed as a “list” to accessibility APIs?

FFS

The listless <menu> element

Between the spec change, and prior to late 2019 / early 2020 if one were to have stumbled across the <menu> element, and attempted to do the following:

<menu>
  <li><a href=...>Some text</a></li>
  <li><button type=button>Some action!</button></li>
  <!-- ... -->
</menu>

they might see what’s rendered, which ‘visually’ looks like an unordered list, and think everything was hunky dory.

The “look” of the unordered list is largely because the <li> element have a default “bullet” list-marker. That’s right, the <li> element defaults to have bullet list-markers, the <ul> element has nothing to do with these list-markers. However, if an <li> is nested within an <ol>, the list-markers default to numerals. Both <ul> and <ol> have an implicit role of list – it is their list-markers which actually are read by screen readers are the indicators of their underlying semantics.

Anyway, if one were to try interacting with the content of these seemingly unordered list items while a screen reader was active, there would be no list semantics of this <menu> element to be found. That’s because browsers had not actually updated the accessibility API mappings to correlate with the <menu> element’s new semantic reality. Keep this in mind, as while sites like caniuse may indicate that an element is “supported”, as it does for <menu>, it is not necessarily an accurate indicator of an element/feature’s accessibility. <menu> needed to expose the implicit ARIA list role to fully make it a semantic equivalent to the <ul> element, as <menu> now found itself re-re-specified as a synonym for. Without that list mapping, not only did <menu> fail to become anything more than a <ul> standin, it wasn’t even doing that properly.

So, bugs were filed. Fast forward to today, and Chromium and Firefox browsers properly expose a <menu> as a list. Webkit doesn’t, but even if they did, styling would probably undo those mappings anyway. So, meh?

Using the <ul>, I mean <menu> element

There are a couple things to consider, if you are planning on using the <menu> element:

  1. Ask yourself “why?” Every pattern that needs list semantics can already be implemented using the <ul> element. Unless you are itching to build something new and use the most semantic HTML in its construction, then no one should be refactoring their markup.
  2. If you are going to use it, because again, “semantically” it would be the appropriate choice for your “toolbar”, then sure… The HTML specification provides a rudimentary example of a text editing toolbar to review:
<menu>
  <li><button onclick="copy()"><img src="copy.svg" alt="Copy"></button></li>
  <li><button onclick="cut()"><img src="cut.svg" alt="Cut"></button></li>
  <li><button onclick="paste()"><img src="paste.svg" alt="Paste"></button></li>
</menu>

But, as far as conveying the expected semantics (where in this instance, “expected semantics” means “expected accessibility properties and features”) and functionality for a robust “toolbar”, we’d need to supplement this pattern with some ARIA and additional JavaScript.

For instance, the ARIA Authoring Practices Note provides an overview of what could be contained within a role=toolbar, which is similar to the <menu>’s suggested content to serve as a “toolbar”… but, again, despite all its wanting for something more over the years, <menu> is just a “list”.

You can review an illustrative example of how a role=toolbar might be constructed and behave, with a variety of nested (custom) form controls, in the Authoring Practice’s toolbar example page.

Taking the HTML specification’s example, and altering it to convey the accessibility semantics of a toolbar, we’d adjust it in the following ways:

<menu role="toolbar"> <!-- 1 -->
  <li role="none"> <!-- 2 -->
    <button onclick="copy()" tabindex="-1"> <!-- 3 -->
      <img src="copy.svg" alt="Copy">
    </button>
  </li>
  <li role="none">
    <button onclick="cut()">
      <img src="cut.svg" alt="Cut">
    </button>
  </li>
  <li role="none">
    <button onclick="paste()" tabindex="-1">
      <img src="paste.svg" alt="Paste">
    </button>
  </li>
</menu>
  1. Overwrite the implicit role=list of the <menu> with the role=toolbar (so much for needing that <menu> element, after all).
  2. While we’re at it, negate the implicit listitem roles of the <li> elements with a role=none. Overwriting the <menu>’s list role should be enough to automatically do that for us, but, just playing it safe…
  3. Implement a roving tabindex script so that the toolbar consists of a single keyboard Tab stop. Arrow keys can then be used to navigate the controls of the toolbar. This Proposal for: a declarative way to get keyboard navigation for focusable element groups sure would be nice here.

Finally ending this

I feel bad for the <menu> element. And by that, I of course mean I feel bad for all the time and effort people have put into trying to make this element something “more”, over the years. All that effort, and it still just ends up as the semantic simile to the <ul>, which was where it started, but wasn’t ever its actual intent. There are a lot of people who worked on this element over the years, and it’s important to recognize that even in getting this element back to square one, there was a lot of thought, time, and likey hard decisions.

But to be honest, I really wrote this post as a sort of counter point to the often uttered phrase “use semantic HTML and you get accessibility for free!” That statement, on its surface, is largely true. And you should use semantic HTML wherever its use is appropriate. <menu>, unfortunately, doesn’t really give us all that much, even though it has clearly defined semantics. Its intended semantics and what we actually need in reality are better served by either just using the more robust <ul> element, or creating your own role=toolbar, menubar, etc.. Using this semantic element, for semantics sake, is just that.

HTML is semantic. There are many elements and attributes that have implicit accessibility role, state and property mappings.

Your semantic HTML, however, is only as accessible as you make it, and maintain it. We still have to be thoughtful about how we write our HTML. We need to understand what it does, and doesn’t do. We will get aspects of accessibility for “free” when we use semantic HTML, but we (and by that I mean the people attempting to use our websites) will pay for it if we assume that using semantic HTML is enough.