diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts
index 9d5328ecb5..abe48e2f6d 100644
--- a/src/compiler/compile/nodes/Element.ts
+++ b/src/compiler/compile/nodes/Element.ts
@@ -556,18 +556,67 @@ export default class Element extends Node {
});
// click-events-have-key-events
- if (handlers_map.has("click")) {
- const hasKeyEvent =
- handlers_map.has("keydown") ||
- handlers_map.has("keyup") ||
- handlers_map.has("keypress");
-
- if (!hasKeyEvent) {
- component.warn(this, {
- code: `a11y-click-events-have-key-events`,
- message: `A11y: on:click event must be accompanied by on:keydown, on:keyup or on:keypress event`
- });
- }
+ if (handlers_map.has('click')) {
+
+ const a11y_interactive = new Set([
+ 'a',
+ 'button',
+ 'select'
+ ]);
+
+ if (a11y_interactive.has(this.name)) {
+ return;
+ }
+
+ if (this.name === 'input') {
+ const input_type = attribute_map.get('type');
+ const input_type_interactive = new Set(['button', 'checkbox', 'color', 'file', 'image', 'radio', 'reset', 'submit']);
+
+ if (input_type && input_type_interactive.has(input_type.get_static_value())) {
+ return;
+ }
+ }
+
+ if (this.attributes.find((attr) => attr.is_spread)) {
+ return;
+ }
+
+ const aria_hidden_attribute = attribute_map.get('aria-hidden');
+ const aria_hidden_value =
+ aria_hidden_attribute && aria_hidden_attribute.get_static_value();
+
+ // aria-hidden value is string, check its boolean value with JSON.parse()
+ if (aria_hidden_value && JSON.parse(aria_hidden_value)) {
+ return;
+ }
+
+ const type_attribute = attribute_map.get('type');
+ const type_value = type_attribute && type_attribute.get_static_value();
+
+ if (type_value && type_value === 'hidden') {
+ return;
+ }
+
+ const role_attribute = attribute_map.get('role');
+ const role_value = role_attribute && role_attribute.get_static_value();
+ const presentation_role_value =
+ role_value === 'presentation' || role_value === 'none';
+
+ if (presentation_role_value) {
+ return;
+ }
+
+ const hasKeyEvent =
+ handlers_map.has('keydown') ||
+ handlers_map.has('keyup') ||
+ handlers_map.has('keypress');
+
+ if (!hasKeyEvent) {
+ component.warn(this, {
+ code: `a11y-click-events-have-key-events`,
+ message: `A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.`
+ });
+ }
}
// no-noninteractive-tabindex
diff --git a/test/validator/samples/a11y-click-events-have-key-events/input.svelte b/test/validator/samples/a11y-click-events-have-key-events/input.svelte
index 4517d6709a..b54392acec 100644
--- a/test/validator/samples/a11y-click-events-have-key-events/input.svelte
+++ b/test/validator/samples/a11y-click-events-have-key-events/input.svelte
@@ -1,15 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+foo
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
diff --git a/test/validator/samples/a11y-click-events-have-key-events/warnings.json b/test/validator/samples/a11y-click-events-have-key-events/warnings.json
index a08b52c114..c0da1e6fcf 100644
--- a/test/validator/samples/a11y-click-events-have-key-events/warnings.json
+++ b/test/validator/samples/a11y-click-events-have-key-events/warnings.json
@@ -1,17 +1,137 @@
[
{
"code": "a11y-click-events-have-key-events",
- "message": "A11y: on:click event must be accompanied by on:keydown, on:keyup or on:keypress event",
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
"end": {
- "character": 85,
+ "character": 102,
"column": 23,
- "line": 6
+ "line": 8
},
"start": {
- "character": 62,
+ "character": 79,
"column": 0,
- "line": 6
+ "line": 8
},
- "pos": 62
+ "pos": 79
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 146,
+ "column": 43,
+ "line": 9
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 103,
+ "start": {
+ "character": 103,
+ "column": 0,
+ "line": 9
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 187,
+ "column": 40,
+ "line": 10
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 147,
+ "start": {
+ "character": 147,
+ "column": 0,
+ "line": 10
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 216,
+ "column": 27,
+ "line": 12
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 189,
+ "start": {
+ "character": 189,
+ "column": 0,
+ "line": 12
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 241,
+ "column": 24,
+ "line": 13
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 217,
+ "start": {
+ "character": 217,
+ "column": 0,
+ "line": 13
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 269,
+ "column": 27,
+ "line": 14
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 242,
+ "start": {
+ "character": 242,
+ "column": 0,
+ "line": 14
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 296,
+ "column": 26,
+ "line": 15
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 270,
+ "start": {
+ "character": 270,
+ "column": 0,
+ "line": 15
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 323,
+ "column": 26,
+ "line": 16
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 297,
+ "start": {
+ "character": 297,
+ "column": 0,
+ "line": 16
+ }
+ },
+ {
+ "code": "a11y-click-events-have-key-events",
+ "end": {
+ "character": 362,
+ "column": 37,
+ "line": 18
+ },
+ "message": "A11y: visible, non-interactive elements with on:click event must be accompanied by a on:keydown, on:keyup or on:keypress event.",
+ "pos": 325,
+ "start": {
+ "character": 325,
+ "column": 0,
+ "line": 18
+ }
}
]