Files
sousa-gecko/testing/web-platform/tests/html/semantics/menu/tentative/menu-elements-tab-focus.optional.html
T
David Baron 8e3514c1dc Bug 2051000 [wpt PR 60939] - Convert menu element structure from command=toggle-menu to DOM nesting., a=testonly
Automatic update from web-platform-tests
Convert menu element structure from command=toggle-menu to DOM nesting.

This makes the changes discussed in
https://github.com/openui/open-ui/issues/1456 and elsewhere to convert
the nesting structure for menu elements from using command=toggle-menu
on menus to represent submenu relationships to using DOM nesting to
represent submenus.

This introduces a <submenu> element that can be used where a <menuitem>
would be, containing two children, the <menuitem> and the associated
<menulist>.  It removes the toggle-menu command, but still allows
<menulist> elements (which are implicitly popovers) that are not inside
a <submenu> to be invoked with a toggle-popover command or the
popovertarget attribute.

This the main change is converting markup that looks like this:

  <menubar>
    <menuitem command=toggle-menu commandfor=file-menu>File</menu>
  </menubar>

  <menulist id=file-menu>
    <menuitem>New</menu>
    <menuitem>Open</menu>
  </menulist>

into this:

  <menubar>
    <submenu>
      <menuitem>File</menuitem>
      <menulist>
        <menuitem>New</menu>
        <menuitem>Open</menu>
      </menulist>
    </submenu>
  </menubar>

The other common pattern that is still permitted (except that it was
previously using the toggle-menu command instead of toggle-popover) is:

  <button command=toggle-popover commandfor=actions-menu>Actions</button>
  <menulist id=actions-menu>
    <menuitem>Go</menuitem>
  </menulist>

Bug: 406566432
Change-Id: If955cb8d3c76f02fca85161a9df3ec182505b1df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7997301
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Reviewed-by: David Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1653560}

--

wpt-commits: aecb1ec9c88346b62e167119b4dab8d8892b6240
wpt-pr: 60939
2026-07-10 09:20:07 +00:00

98 lines
3.6 KiB
HTML

<!DOCTYPE html>
<link rel=author href="mailto:jarhar@chromium.org">
<link rel=help href="https://github.com/openui/open-ui/issues/1438">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<!-- This test is marked as optional because this tab key behavior is not
explicitly specified. -->
<button id=beforemenu>before menus</button>
<menubar id=menubar>
<submenu>
<menuitem id=menubaritem1>open menulist1</menuitem>
<menulist id=menulist1>
<submenu>
<menuitem id=menulist1item1>open menulist2</menuitem>
<menulist id=menulist2>
<menuitem id=menulist2item1>menuitem one</menuitem>
<menuitem id=menulist2item2>menuitem two</menuitem>
</menulist>
</submenu>
<menuitem id=menulist1item2>menuitem two</menuitem>
</menulist>
</submenu>
<menuitem id=menubaritem2>menuitem two</menuitem>
</menubar>
<button id=aftermenu>after menus</button>
<script>
const tab = '\uE004';
const enter = '\uE007';
const shift = '\uE008';
function pressKey(firstKey, secondKey) {
const actions = new test_driver.Actions();
actions.keyDown(firstKey);
if (secondKey) {
actions.keyDown(secondKey);
actions.keyUp(secondKey);
}
actions.keyUp(firstKey);
return actions.send();
}
const beforemenu = document.getElementById('beforemenu');
const aftermenu = document.getElementById('aftermenu');
const menubar = document.getElementById('menubar');
const menulist1 = document.getElementById('menulist1');
const menulist2 = document.getElementById('menulist2');
const menubaritem1 = document.getElementById('menubaritem1');
const menulist1item1 = document.getElementById('menulist1item1');
const menulist2item1 = document.getElementById('menulist2item1');
promise_test(async () => {
beforemenu.focus();
await pressKey(tab);
assert_equals(document.activeElement, menubaritem1,
'Tabbing into a menubar should focus the first focusable menuitem.');
await pressKey(tab);
assert_equals(document.activeElement, aftermenu,
'Tabbing out of a menubar should focus the next focusable item after the menubar.');
await pressKey(shift, tab);
assert_equals(document.activeElement, menubaritem1,
'Shift+tabbing into a menubar should focus the first focusable menuitem.');
menulist1.showPopover({source: menubaritem1});
menulist1item1.focus();
await pressKey(tab);
assert_false(menulist1.matches(':popover-open'),
'Tab key should close menulist.');
assert_equals(document.activeElement, aftermenu,
'Tab key should move focus to next focusable item after menus.');
menulist1.showPopover({source: menubaritem1});
menulist1item1.focus();
await pressKey(shift, tab);
assert_false(menulist1.matches(':popover-open'),
'Shift+tab key should close menulist.');
assert_equals(document.activeElement, beforemenu,
'Shift+tab key should move focus to previous item before menus.');
menulist1.showPopover({source: menubaritem1});
menulist2.showPopover({source: menulist1item1});
menulist2item1.focus();
await pressKey(tab);
assert_false(menulist2.matches(':popover-open'),
'Tab key should close outer menulist.');
assert_false(menulist1.matches(':popover-open'),
'Tab key should close inner menulist.');
assert_equals(document.activeElement, aftermenu,
'Tab key should move focus to the next focusable item after menus in nested case.');
}, 'Tab and shift+tab behavior in and around menu elements.');
</script>