v143 · html · menus

<menubar>, <menulist>, <menuitem>

The existing <menu> element is a list with a misleading name — it is exposed as a list, behaves as a list, and has never been a menu to anything that reads the page. Three new elements give the platform an actual menu: a bar, a list that opens as a popover, and an item that invokes a command.

concepts

  1. What actually landed

    A draft specification and a partial implementation rarely line up. Read each element's real interface, its user-agent styling, and which pieces of the proposal this browser has — measured from the elements themselves rather than from the explainer.

  2. A working menu bar

    File, Edit, View, built out of the elements and opened with invoker commands rather than script. Keyboard-operable, with the fallback shown honestly when the browser does not know the elements.

  3. Commands, checkboxes and radios

    Menu items carry state as well as actions. Probe the command vocabulary by reflection, and see which of type, checked and fieldset checkable are implemented here — the answer is more interesting than yes.

why it shipped

Every application on the web that has a menu has built it out of buttons and divs, plus a few hundred lines of ARIA and key handling. The result is nearly always subtly wrong: the roving tabindex misses a case, typeahead is missing, Escape closes the wrong layer, and a screen reader announces a list of links.

The new elements move that into the platform. A <menulist> opens in the top layer without a popover attribute, a <menuitem> invokes a command through commandfor rather than a click handler, and the roles come from the elements instead of from attributes someone has to remember to write.

the markup

<menubar>
  <menuitem command="toggle-menu" commandfor="file-menu">File</menuitem>
  <menulist id="file-menu">
    <menuitem command="--new-document" commandfor="editor">New</menuitem>
    <menuitem command="--open" commandfor="editor">Open…</menuitem>
  </menulist>
</menubar>

No role, no tabindex, no key handler, and no popover attribute — the menulist opens into the top layer because of what it is.

enabling it now

Verified on Chrome 150 on this machine: with the flag off, document.createElement("menuitem") produces an HTMLUnknownElement. With it on, the three elements have their own interfaces, <menubar> gets display: inline-flex from the user-agent stylesheet, a <menulist> is display: none until it is invoked, and invoking one makes it match :popover-open.

chrome://flags/#enable-experimental-web-platform-features

# or, from the command line
google-chrome --enable-experimental-web-platform-features

references