darryl@dpogue

HTML5 Menus & Browser Support

Last Updated on

The <menu> tag has a bit of a troubled history. In HTML3 it was essentially synonymous with <ul>. It was deprecated in HTML4, but added back to the specification for HTML5. Due to feedback from browser makers, it changed a bit between the publishing of the W3C HTML5 spec and the continued work on the WHATWG HTML5.1 spec.

The purpose of the <menu> tag is to allow web applications to provide context menu actions that will be merged into the browser's native context menu. This is something that has been implemented using JavaScript libraries for years, but the advantage of native support is that it doesn't prevent access to the existing browser menus.

Support is a bit lacking at this point, but there's definite progress in a few browsers. There are actually a few different pieces of menu-related support that we're interested in knowing about:

  • Support for the basic <menu> tag (type="toolbar")
  • Support for the popup <menu> tag (type="context")
  • Support for the <menuitem> tag
  • Support for the contextmenu attribute

There was previously a <button type="menu"> in the spec to allow opening context menus via buttons, but that has been removed as of February 2017. Unfortunately, that severely limits the usefulness of the <menu> tag.

If you're curious to know more, the rest of the post will explain the spec and how the <menu> tag can be used. If you're just interested in knowing current browser support for the above features, here's the support matrix:

Browser support for HTML5 Menus
Firefox Chrome Safari Edge Android Chrome iOS Safari
toolbar menu Partial Yes (Flag) Partial Partial Yes (Flag) Partial
popup menu Yes Yes (Flag) No No Yes (Flag) No
menuitem Partial Yes (Flag) No No Yes (Flag) No
contextmenu Yes Yes (Flag) No No Partial (Flag) No

Note: Chrome support is limited to Chrome 48+ running with --enable-blink-features=ContextMenu.
Between Chrome 48 and 52, it was enabled behind the "Experimental Web Platforms" feature flag.

Making Sense of Menus

Toolbar menu
A simple toolbar menu, as rendered in Chrome.

The most basic case of the <menu> tag is using it as it was used back in the HTML3 days to provide a list of links. Its children should be <li> list items with links or buttons inside. This is the default type of menu, and is supported by all browsers. In most cases, it looks identical to a <ul> list.

In HTML5, the <menu> element has a type attribute that determines which type of menu is being defined. The default value for type is "toolbar", which preserves the list-like appearance from HTML3.

Note: Neither Chrome nor Firefox properly implement the default value for the type attribute on <menu> elements.
Chrome does not implement the type attribute at all unless the "Experimental Web Platform Features" flag is enabled.
Firefox returns an older (now incorrect) default value of "list" for the type attribute.

A basic example of sidebar link using <menu> might look something like this:

<menu type="toolbar">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
</menu>

Making Use of HTML5

Context menu
A simple popup context menu, as rendered in Chrome.

Beyond being compatible with HTML3, the HTML5 <menu> tag is intended to add custom context actions to right-click/long-press popup menus in the browser. To define a popup menu, you need to set the type attribute to "context".

Popup <menu> elements are intended to be combined with the global contextmenu attribute. You can specify contextmenu on any element in your page and set its value to the ID of a <menu> in the same DOM hierarchy, and when the contextmenu event is triggered on that element it will show the specified <menu>.

Note: Chrome on Android supports the contextmenu attribute, but does not enable long-press on the elements. Therefore, you can only bring up the menu on a element that already has long-press support (like an <a> tag).

As an example, this is how you might associate a menu with a <div>:

<div contextmenu="myMenu">Right-click Me</div>

<menu type="context" id="myMenu">
</menu>

Now this menu doesn't really accomplish much because it's empty. To add actions to our menu, we need to use the <menuitem> tag. This element is optionally self-closing (like <li> or <options>) and does not require a closing tag if it is followed by another <menuitem>, a <menu>, or the end tag of its parent element.

Note: Firefox doesn't treat <menuitem> as self-closing properly at the moment, so to be safe I'd recommend including a closing tag.

The <menuitem> tag is modelled after the <option> tag. The first and most important attribute is label. This is the text that you want to appear in your popup menu. If no label attribute is specified, the text content of the element will be used as the label.

The simplest menu item looks like this:

<menuitem label="Menu Item 1">

Some other basic attributes for <menuitem> include:

  • icon: Adds an icon to the menu when the icon value is the URL of an image.
  • disabled: Visually disables and prevents clicking on the menu item.
  • title: Provides a hint describing the item action, which may be displayed as a tooltip.

Note: Chrome doesn't support the icon attribute at the moment.
I don't think any browsers support the title attribute.

Our example might now look something like this:

<div contextmenu="myMenu">Right-Click Me</div>
<menu type="context" id="myMenu">
    <menuitem label="Item 1" title="The first menu item">
    <menuitem label="Item 2" title="The second menu item" disabled>
</menu>

More complicated menu items

Complex context menu
A context menu with checkbox items and separators.

Often menus are used by applications to present a quick way to enable or disable options, or to toggle between a few different options. We can do that in HTML too by looking at some of the advanced attributes for the <menuitem> tag.

For menu items that can be toggled on and off (like a checkbox), set the type attribute to "checkbox". You can specify if the item is checked by default using the checked attribute.

For items that behave like a radio button group, set the type attribute to "radio", and give all the items the same radiogroup value. You can specify which item should be checked by default with the checked attribute.

You can also group menu items by adding separators with an <hr> element.

Our more complicated example looks like this:

<menu type="context" id="myMenu">
    <menuitem type="checkbox" label="Enable CSS" checked>
    <menuitem type="checkbox" label="Enable JS">
    <hr>
    <menuitem type="radio" radiogroup="img" label="PNG" checked>
    <menuitem type="radio" radiogroup="img" label="JPEG">
    <menuitem type="radio" radiogroup="img" label="GIF">
</menu>

There's one more type of menu item, a "command" type that references another element in the page by ID and triggers it with a click event when the menu item is activated.

<button id="submitbutton" type="submit">Submit</button>

<menu type="context">
    <menuitem type="command" command="submitbutton" label="Submit">
</menu>

Nested Menus

Context submenu
A context menu with a nested submenu.

You can create submenus by nesting <menu> elements within each other. When creating a child menu, you must specify the label attribute on the child <menu>. This label will be displayed as a menu item that opens the child menu.

Example:

<div contextmenu="myMenu">Right-Click Me</div>
<menu type="context" id="myMenu">
    <menu label="Child Menu">
        <menuitem label="Child Item 1">
        <menuitem label="Child Item 2">
    </menu>
</menu>

Opening Menus With Buttons

Much to my dismay, this feature is missing in all browsers and – as of February 2017 – has been entirely dropped from the HTML5 spec.

The HTML5 spec proposed adding a new type of <button> for opening menus when activated. If the button type attribute is "menu" and the menu attribute is the ID of a popup <menu> tag, clicking or tapping the button should open the menu.

This is where the real value of menus can be used, combining a <menu type="toolbar"> containing <button type="menu"> elements with <menu type="context"> elements to build a standard-style menu bar using only standards-based HTML.

(Not working) example:

<button type="menu" menu="myMenu">Click Me</button>

<menu type="context" id="myMenu">
    <menuitem label="Item 1">
    <menuitem label="Item 2">
</menu>

I worked on a JS polyfill for this missing feature, which you can find as ay-menu-button on npm.

Changelog

  • : Updated to reflect that WHATWG have broken my heart by dropping <button type="menu"> from the spec.
  • : Updated to reflect Chrome moving the feature behind more flags in Chrome 52.
  • : Updated to reflect the loosened <menuitem> text content rules.
  • : Updated to reflect Chrome 48 support for type="context".
  • : Updated to reflect that the spec has been changed from type="popup" back to type="context".
  • : Originally published.

Comments