@@ -38,7 +38,13 @@ function isCompositeWidgetPattern(parentRole, childRole) {
3838}
3939
4040function isMenuItemNode ( node ) {
41- return getTextAttr ( node , 'role' ) === 'menuitem' ;
41+ // Match all three menu-item role variants per ARIA taxonomy. `menuitem`,
42+ // `menuitemcheckbox`, and `menuitemradio` are all "menu items" — they can
43+ // carry submenus (via MENUITEM_ROLES in isCompositeWidgetPattern) and nest
44+ // each other (via the nested-menuitem compat exception). Keeping both
45+ // predicates symmetric avoids false positives on APG Menu Button /
46+ // Menubar patterns that mix the variants.
47+ return MENUITEM_ROLES . has ( getTextAttr ( node , 'role' ) ) ;
4248}
4349
4450function isAllowedDetailsChild ( childNode , parentEntry ) {
@@ -225,9 +231,10 @@ module.exports = {
225231 // Derived from aria-query's requiredOwnedElements with superClass
226232 // inheritance — see lib/utils/interactive-roles.js.
227233 } else if ( isMenuItemNode ( parentEntry . node ) && isMenuItemNode ( node ) ) {
228- // Nested menuitem nodes are valid (menu/sub-menu pattern) — kept
229- // for historical compat since aria-query doesn't encode this via
230- // requiredOwnedElements.
234+ // Nested menu-item nodes (any combination of menuitem /
235+ // menuitemcheckbox / menuitemradio) are valid — menu/sub-menu
236+ // pattern per WAI-ARIA APG. Kept for historical compat since
237+ // aria-query doesn't encode this via requiredOwnedElements.
231238 } else {
232239 context . report ( {
233240 node,
0 commit comments