diff --git a/.changeset/fix-menu-element-a11y-roles.md b/.changeset/fix-menu-element-a11y-roles.md
new file mode 100644
index 0000000000..75cfe8d310
--- /dev/null
+++ b/.changeset/fix-menu-element-a11y-roles.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: treat `
` like ` `/`` for a11y role checks
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js
index 684ea92094..49099c2cb1 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js
@@ -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'],
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
index f5f4982ed2..45de8b10a1 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js
@@ -167,7 +167,7 @@ export function check_element(node, context) {
if (
current_role === get_implicit_role(node.name, attribute_map) &&
// 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) &&
// is ok because without href the a tag doesn't have a role of link
!(node.name === 'a' && !attribute_map.has('href'))
) {
diff --git a/packages/svelte/tests/validator/samples/a11y-no-noninteractive-element-to-interactive-role/input.svelte b/packages/svelte/tests/validator/samples/a11y-no-noninteractive-element-to-interactive-role/input.svelte
index e5db8719b0..edfa3eeada 100644
--- a/packages/svelte/tests/validator/samples/a11y-no-noninteractive-element-to-interactive-role/input.svelte
+++ b/packages/svelte/tests/validator/samples/a11y-no-noninteractive-element-to-interactive-role/input.svelte
@@ -69,6 +69,13 @@
+
+
+
+
+
+
+
diff --git a/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/input.svelte b/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/input.svelte
index 2ccd765aa2..9e06ebe420 100644
--- a/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/input.svelte
+++ b/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/input.svelte
@@ -22,7 +22,7 @@
-
+
@@ -44,5 +44,5 @@
-
+
diff --git a/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/warnings.json b/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/warnings.json
index 861f000aef..e041037d71 100644
--- a/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/warnings.json
+++ b/packages/svelte/tests/validator/samples/a11y-no-redundant-roles/warnings.json
@@ -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": {