fix: treat menu element like ul/ol for a11y role checks (#17638)

* treat menu element like ul/ol for a11y role checks

The <menu> element has the same implicit role (list) as <ul> and <ol>,
so it should receive the same treatment in a11y checks:

- Allow <menu role="list"> without redundant role warning (CSS
  list-style:none can remove semantics, role restores them)
- Allow <menu> with interactive roles like menu, menubar, radiogroup,
  tablist, tree, treegrid (same exceptions as ul/ol)

Fixes #8529

* changeset

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
pull/17644/head
Artyom Alekseevich 6 months ago committed by GitHub
parent 4453e4895d
commit f71a6813b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: treat `<menu>` like `<ul>`/`<ol>` for a11y role checks

@ -174,6 +174,7 @@ export const input_type_to_implicit_role = new Map([
export const a11y_non_interactive_element_to_interactive_role_exceptions = {
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
menu: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
table: ['grid'],
td: ['gridcell'],

@ -167,7 +167,7 @@ export function check_element(node, context) {
if (
current_role === get_implicit_role(node.name, attribute_map) &&
// <ul role="list"> is ok because CSS list-style:none removes the semantics and this is a way to bring them back
!['ul', 'ol', 'li'].includes(node.name) &&
!['ul', 'ol', 'li', 'menu'].includes(node.name) &&
// <a role="link" /> is ok because without href the a tag doesn't have a role of link
!(node.name === 'a' && !attribute_map.has('href'))
) {

@ -69,6 +69,13 @@
<li role="menuitem"></li>
<li role="row"></li>
<li role="treeitem" aria-selected={false}></li>
<!-- menu -->
<menu role="menu"></menu>
<menu role="menubar"></menu>
<menu role="radiogroup"></menu>
<menu role="tablist"></menu>
<menu role="tree"></menu>
<menu role="treegrid"></menu>
<!-- VALID: elements assigned an interactive role. -->
<div role="button"></div>

@ -22,7 +22,7 @@
<!-- <li role="listitem" /> allowed since CSS list-style none removes semantic meaning and role brings it back -->
<link role="link" />
<main role="main"></main>
<menu role="list"></menu>
<!-- <menu role="list" /> allowed, same as ul/ol above -->
<nav role="navigation"></nav>
<!-- <ol role="list" /> allowed, see comment above -->
<optgroup role="group"></optgroup>
@ -44,5 +44,5 @@
<footer role="contentinfo"></footer>
<!-- Allowed -->
<!-- svelte-ignore a11y_no_noninteractive_element_to_interactive_role -->
<!-- menu has same interactive role exceptions as ul/ol -->
<menu role="menu"></menu>

@ -275,18 +275,6 @@
"line": 24
}
},
{
"code": "a11y_no_redundant_roles",
"end": {
"column": 17,
"line": 25
},
"message": "Redundant role 'list'",
"start": {
"column": 6,
"line": 25
}
},
{
"code": "a11y_no_redundant_roles",
"end": {

Loading…
Cancel
Save