Repository: biomejs/biome (language: rust)

Issue:
📎 Implement `jsx-a11y/no-noninteractive-element-interactions`
### Description

Implement [jsx-a11y/no-noninteractive-element-interactions](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-interactions.md)

**Want to contribute?** Lets you know you are interested! We will assign you to the issue to prevent several people to work on the same issue. Don't worry, we can unassign you later if you are no longer interested in the issue! Read our [contributing guide](https://github.com/biomejs/biome/blob/main/CONTRIBUTING.md) and [analyzer contributing guide](https://github.com/biomejs/biome/blob/main/crates/biome_analyze/CONTRIBUTING.md).


Discussion / hints:
Hello.
Can I work on this?
All yours @tunamaguro 

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 7440d548f858..8529d8663a71 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -865,6 +865,7 @@ name = "biome_js_syntax"
 version = "0.5.7"
 dependencies = [
  "biome_aria",
+ "biome_aria_metadata",
  "biome_js_factory",
  "biome_js_parser",
  "biome_rowan",
diff --git a/crates/biome_aria/src/roles.rs b/crates/biome_aria/src/roles.rs
index 933b3c7c1007..e2c2bb99a201 100644
--- a/crates/biome_aria/src/roles.rs
+++ b/crates/biome_aria/src/roles.rs
@@ -238,7 +238,7 @@ impl AriaRoles {
 
     /// Given an element name and attributes, it returns the role associated with that element.
     /// If no explicit role attribute is present, an implicit role is returned.
-    fn get_role_by_element_name(&self, element: &impl Element) -> Option<AriaRole> {
+    pub fn get_role_by_element_name(&self, element: &impl Element) -> Option<AriaRole> {
         element
             .find_attribute_by_name(|name| name == "role")
             .as_ref()
diff --git a/crates/biome_aria_metadata/src/lib.rs b/crates/biome_aria_metadata/src/lib.rs
index deeb4708c463..3ffacd646013 100644
--- a/crates/biome_aria_metadata/src/lib.rs
+++ b/crates/biome_aria_metadata/src/lib.rs
@@ -129,7 +129,7 @@ fn is_valid_html_id(id: &str) -> bool {
 }
 
 impl AriaRole {
-    /// Returns the first valid role from `values`, a space-separated list of roles.
+    /// Returns the first valid role from `roles`, a space-separated list of roles.
     ///
     /// If a role attribute has multiple values, the first valid role (specified role) will be used.
     /// See <https://www.w3.org/TR/2014/REC-wai-aria-implementation-20140320/#mapping_role>
diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
index 0e172eed1c2d..d80d70fa886f 100644
--- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
+++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
@@ -734,6 +734,16 @@ pub(crate) fn migrate_eslint_any_rule(
                 .get_or_insert(Default::default());
             rule.set_level(rule_severity.into());
         }
+        "jsx-a11y/no-noninteractive-element-interactions" => {
+            if !options.include_nursery {
+                return false;
+            }
+            let group = rules.nursery.get_or_insert_with(Default::default);
+            let rule = group
+                .no_noninteractive_element_interactions
+                .get_or_insert(Default::default());
+            rule.set_level(rule_severity.into());
+        }
         "jsx-a11y/no-noninteractive-element-to-interactive-role" => {
             let group = rules.a11y.get_or_insert_with(Default::default);
             let rule = group
diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs
index 03cf4720e77e..31404f0b2468 100644
--- a/crates/biome_configuration/src/analyzer/linter/rules.rs
+++ b/crates/biome_configuration/src/analyzer/linter/rules.rs
@@ -3337,6 +3337,10 @@ pub struct Nursery {
     #[doc = "Disallow nested ternary expressions."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_nested_ternary: Option<RuleConfiguration<biome_js_analyze::options::NoNestedTernary>>,
+    #[doc = "Disallow use event handlers on non-interactive elements."]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub no_noninteractive_element_interactions:
+        Option<RuleConfiguration<biome_js_analyze::options::NoNoninteractiveElementInteractions>>,
     #[doc = "Disallow octal escape sequences in string literals"]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_octal_escape: Option<RuleConfiguration<biome_js_analyze::options::NoOctalEscape>>,
@@ -3512,6 +3516,7 @@ impl Nursery {
         "noIrregularWhitespace",
         "noMissingVarFunction",
         "noNestedTernary",
+        "noNoninteractiveElementInteractions",
         "noOctalEscape",
         "noProcessEnv",
         "noProcessGlobal",
@@ -3577,17 +3582,17 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[7]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]),
     ];
     const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
@@ -3646,6 +3651,7 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56]),
     ];
     #[doc = r" Retrieves the recommended rules"]
     pub(crate) fn is_recommended_true(&self) -> bool {
@@ -3752,196 +3758,201 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
             }
         }
-        if let Some(rule) = self.no_octal_escape.as_ref() {
+        if let Some(rule) = self.no_noninteractive_element_interactions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
             }
         }
-        if let Some(rule) = self.no_process_env.as_ref() {
+        if let Some(rule) = self.no_octal_escape.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
             }
         }
-        if let Some(rule) = self.no_process_global.as_ref() {
+        if let Some(rule) = self.no_process_env.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
             }
         }
-        if let Some(rule) = self.no_restricted_imports.as_ref() {
+        if let Some(rule) = self.no_process_global.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
             }
         }
-        if let Some(rule) = self.no_restricted_types.as_ref() {
+        if let Some(rule) = self.no_restricted_imports.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
             }
         }
-        if let Some(rule) = self.no_secrets.as_ref() {
+        if let Some(rule) = self.no_restricted_types.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
             }
         }
-        if let Some(rule) = self.no_static_element_interactions.as_ref() {
+        if let Some(rule) = self.no_secrets.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
             }
         }
-        if let Some(rule) = self.no_substr.as_ref() {
+        if let Some(rule) = self.no_static_element_interactions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
             }
         }
-        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
+        if let Some(rule) = self.no_substr.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
             }
         }
-        if let Some(rule) = self.no_unknown_at_rule.as_ref() {
+        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
+        if let Some(rule) = self.no_unknown_at_rule.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
+        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.no_useless_string_raw.as_ref() {
+        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.no_useless_undefined.as_ref() {
+        if let Some(rule) = self.no_useless_string_raw.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_exports_last.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_exports_last.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]));
             }
         }
-        if let Some(rule) = self.use_named_operation.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]));
             }
         }
-        if let Some(rule) = self.use_naming_convention.as_ref() {
+        if let Some(rule) = self.use_named_operation.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]));
             }
         }
-        if let Some(rule) = self.use_parse_int_radix.as_ref() {
+        if let Some(rule) = self.use_naming_convention.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_parse_int_radix.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_enabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56]));
+            }
+        }
         index_set
     }
     pub(crate) fn get_disabled_rules(&self) -> FxHashSet<RuleFilter<'static>> {
@@ -4036,196 +4047,201 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
             }
         }
-        if let Some(rule) = self.no_octal_escape.as_ref() {
+        if let Some(rule) = self.no_noninteractive_element_interactions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
             }
         }
-        if let Some(rule) = self.no_process_env.as_ref() {
+        if let Some(rule) = self.no_octal_escape.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
             }
         }
-        if let Some(rule) = self.no_process_global.as_ref() {
+        if let Some(rule) = self.no_process_env.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
             }
         }
-        if let Some(rule) = self.no_restricted_imports.as_ref() {
+        if let Some(rule) = self.no_process_global.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
             }
         }
-        if let Some(rule) = self.no_restricted_types.as_ref() {
+        if let Some(rule) = self.no_restricted_imports.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
             }
         }
-        if let Some(rule) = self.no_secrets.as_ref() {
+        if let Some(rule) = self.no_restricted_types.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
             }
         }
-        if let Some(rule) = self.no_static_element_interactions.as_ref() {
+        if let Some(rule) = self.no_secrets.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
             }
         }
-        if let Some(rule) = self.no_substr.as_ref() {
+        if let Some(rule) = self.no_static_element_interactions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
             }
         }
-        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
+        if let Some(rule) = self.no_substr.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
             }
         }
-        if let Some(rule) = self.no_unknown_at_rule.as_ref() {
+        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
+        if let Some(rule) = self.no_unknown_at_rule.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
+        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.no_useless_string_raw.as_ref() {
+        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.no_useless_undefined.as_ref() {
+        if let Some(rule) = self.no_useless_string_raw.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_exports_last.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_exports_last.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]));
             }
         }
-        if let Some(rule) = self.use_named_operation.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]));
             }
         }
-        if let Some(rule) = self.use_naming_convention.as_ref() {
+        if let Some(rule) = self.use_named_operation.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]));
             }
         }
-        if let Some(rule) = self.use_parse_int_radix.as_ref() {
+        if let Some(rule) = self.use_naming_convention.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_parse_int_radix.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_disabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56]));
+            }
+        }
         index_set
     }
     #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"]
@@ -4334,6 +4350,10 @@ impl Nursery {
                 .no_nested_ternary
                 .as_ref()
                 .map(|conf| (conf.level(), conf.get_options())),
+            "noNoninteractiveElementInteractions" => self
+                .no_noninteractive_element_interactions
+                .as_ref()
+                .map(|conf| (conf.level(), conf.get_options())),
             "noOctalEscape" => self
                 .no_octal_escape
                 .as_ref()
diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs
index 6c9199a53c4c..b3e5cb63c86e 100644
--- a/crates/biome_diagnostics_categories/src/categories.rs
+++ b/crates/biome_diagnostics_categories/src/categories.rs
@@ -160,6 +160,7 @@ define_categories! {
     "lint/nursery/noMissingGenericFamilyKeyword": "https://biomejs.dev/linter/rules/no-missing-generic-family-keyword",
     "lint/nursery/noMissingVarFunction": "https://biomejs.dev/linter/rules/no-missing-var-function",
     "lint/nursery/noNestedTernary": "https://biomejs.dev/linter/rules/no-nested-ternary",
+    "lint/nursery/noNoninteractiveElementInteractions": "https://biomejs.dev/linter/rules/no-noninteractive-element-interactions",
     "lint/nursery/noOctalEscape": "https://biomejs.dev/linter/rules/no-octal-escape",
     "lint/nursery/noProcessEnv": "https://biomejs.dev/linter/rules/no-process-env",
     "lint/nursery/noProcessGlobal": "https://biomejs.dev/linter/rules/no-process-global",
diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs
index f66f4761c1d3..feca74ece6b8 100644
--- a/crates/biome_js_analyze/src/lint/nursery.rs
+++ b/crates/biome_js_analyze/src/lint/nursery.rs
@@ -15,6 +15,7 @@ pub mod no_head_import_in_document;
 pub mod no_img_element;
 pub mod no_irregular_whitespace;
 pub mod no_nested_ternary;
+pub mod no_noninteractive_element_interactions;
 pub mod no_octal_escape;
 pub mod no_process_env;
 pub mod no_process_global;
@@ -63,6 +64,7 @@ declare_lint_group! {
             self :: no_img_element :: NoImgElement ,
             self :: no_irregular_whitespace :: NoIrregularWhitespace ,
             self :: no_nested_ternary :: NoNestedTernary ,
+            self :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions ,
             self :: no_octal_escape :: NoOctalEscape ,
             self :: no_process_env :: NoProcessEnv ,
             self :: no_process_global :: NoProcessGlobal ,
diff --git a/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs b/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs
new file mode 100644
index 000000000000..fbbd43dd80d0
--- /dev/null
+++ b/crates/biome_js_analyze/src/lint/nursery/no_noninteractive_element_interactions.rs
@@ -0,0 +1,215 @@
+use crate::services::aria::Aria;
+use biome_analyze::{context::RuleContext, declare_lint_rule, Rule, RuleDiagnostic, RuleSource};
+use biome_console::markup;
+use biome_js_syntax::jsx_ext::AnyJsxElement;
+use biome_rowan::AstNode;
+
+declare_lint_rule! {
+    /// Disallow use event handlers on non-interactive elements.
+    ///
+    /// Non-interactive HTML elements indicate _content_ and _containers_ in the user interface.
+    /// Non-interactive elements include `<main>`, `<area>`, `<h1>` (,`<h2>`, etc), `<img>`, `<li>`, `<ul>` and `<ol>`.
+    ///
+    /// A Non-interactive element does not support event handlers(mouse and key handlers).
+    ///
+    ///
+    /// ## Examples
+    ///
+    /// ### Invalid
+    ///
+    /// ```jsx,expect_diagnostic
+    /// <div onClick={() => {}}>button</div>
+    /// ```
+    ///
+    /// ### Valid
+    ///
+    /// ```jsx
+    /// <button onClick={() => { }}>button</button>
+    /// ```
+    ///
+    /// ```jsx
+    /// // Adding a role to element does not add behavior.
+    /// // If not used semantic HTML elements like `button`, developers need to implement the expected behavior for role(like focusability and key press support)
+    /// // See https://www.w3.org/WAI/ARIA/apg/
+    /// <div role="button" onClick={() => { }}>button</div>
+    /// ```
+    ///
+    /// ```jsx
+    /// // The role="presentation" attribute removes the semantic meaning of an element, indicating that it should be ignored by assistive technologies.
+    /// // Therefore, it's acceptable to add event handlers to elements with role="presentation" for visual effects or other purposes,
+    /// // but users relying on assistive technologies may not be able to interact with these elements.
+    /// <div role="presentation" onClick={() => { }}>button</div>
+    /// ```
+    ///
+    /// ```jsx
+    /// // Hidden from screen reader.
+    /// <div onClick={() => {}} aria-hidden />
+    /// ```
+    ///
+    /// ```jsx
+    /// // Custom component is not checked.
+    /// <SomeComponent onClick={() => {}}>button</SomeComponent>
+    /// ```
+    ///
+    /// ```jsx
+    /// // Spread attributes is not supported.
+    /// <div {...{"onClick":() => {}}}>button</div>
+    /// ```
+    ///
+    /// ## Accessibility guidelines
+    ///
+    /// - [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value)
+    ///
+    /// ### Resources
+    ///
+    /// - [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#usage_intro)
+    /// - [WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_ex)
+    /// - [Fundamental Keyboard Navigation Conventions](https://www.w3.org/TR/wai-aria-practices-1.1/#kbd_generalnav)
+    /// - [Mozilla Developer Network - ARIA Techniques](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Keyboard_and_focus)
+    ///
+    pub NoNoninteractiveElementInteractions {
+        version: "next",
+        name: "noNoninteractiveElementInteractions",
+        language: "jsx",
+        sources: &[RuleSource::EslintJsxA11y("no-noninteractive-element-interactions")],
+        recommended: false,
+    }
+}
+
+impl Rule for NoNoninteractiveElementInteractions {
+    type Query = Aria<AnyJsxElement>;
+    type State = ();
+    type Signals = Option<Self::State>;
+    type Options = ();
+
+    fn run(ctx: &RuleContext<Self>) -> Self::Signals {
+        let element = ctx.query();
+
+        // Custom components are not checked because we do not know what DOM will be used.
+        if element.is_custom_component() {
+            return None;
+        }
+
+        let aria_roles = ctx.aria_roles();
+        let role = aria_roles.get_role_by_element_name(element);
+        let has_interactive_role = role.is_some_and(|role| role.is_interactive());
+
+        if !has_handler_props(element)
+            || is_content_editable(element)
+            || has_presentation_role(element)
+            || is_hidden_from_screen_reader(element)?
+            || has_interactive_role
+        {
+            return None;
+        }
+
+        // Non-interactive elements what contains event handler should be reported.
+        if has_handler_props(element) && aria_roles.is_not_interactive_element(element) {
+            return Some(());
+        };
+
+        None
+    }
+
+    fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
+        let node = ctx.query();
+        Some(
+            RuleDiagnostic::new(
+                rule_category!(),
+                node.range(),
+                markup! {
+                    "Non-interactive element should not have event handler."
+                },
+            )
+            .note(markup! {
+                "Consider replace semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
+            })
+        )
+    }
+}
+
+/// Ref: https://github.com/jsx-eslint/jsx-ast-utils/blob/v3.3.5/src/eventHandlers.js
+const INTERACTIVE_HANDLERS: &[&str] = &[
+    "onClick",
+    "onContextMenu",
+    "onDblClick",
+    "onDoubleClick",
+    "onDrag",
+    "onDragEnd",
+    "onDragEnter",
+    "onDragExit",
+    "onDragLeave",
+    "onDragOver",
+    "onDragStart",
+    "onDrop",
+    "onMouseDown",
+    "onMouseEnter",
+    "onMouseLeave",
+    "onMouseMove",
+    "onMouseOut",
+    "onMouseOver",
+    "onKeyDown",
+    "onKeyPress",
+    "onKeyUp",
+    "onFocus",
+    "onBlur",
+    "onLoad",
+    "onError",
+];
+
+/// Check if the element contains event handler
+fn has_handler_props(element: &AnyJsxElement) -> bool {
+    INTERACTIVE_HANDLERS
+        .iter()
+        .any(|handler| element.find_attribute_by_name(handler).is_some())
+}
+
+/// Check if the element's implicit ARIA semantics have been removed.
+/// See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/presentation_role
+///
+/// Ref: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.10.0/src/util/isPresentationRole.js
+fn has_presentation_role(element: &AnyJsxElement) -> bool {
+    if let Some(attribute) = element.find_attribute_by_name("role") {
+        let value = attribute.as_static_value();
+        if let Some(value) = value {
+            return matches!(value.as_string_constant(), Some("presentation" | "none"));
+        }
+    }
+    false
+}
+
+/// Check the element is hidden from screen reader.
+/// See
+/// - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden
+/// - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/hidden
+///
+/// Ref: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.10.0/src/util/isHiddenFromScreenReader.js
+fn is_hidden_from_screen_reader(element_name: &AnyJsxElement) -> Option<bool> {
+    let is_aria_hidden = element_name.has_truthy_attribute("aria-hidden");
+
+    let name = element_name.name_value_token().ok()?;
+
+    let is_input_hidden = if name.text_trimmed() == "input" {
+        element_name
+            .find_attribute_by_name("type")
+            .and_then(|attribute| attribute.as_static_value())
+            .and_then(|value| value.as_string_constant().map(|value| value == "hidden"))
+            .unwrap_or_default()
+    } else {
+        false
+    };
+
+    Some(is_aria_hidden || is_input_hidden)
+}
+
+/// Check if the element is `contentEditable`
+/// See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable
+///
+/// Ref: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.10.0/src/util/isContentEditable.js
+fn is_content_editable(element: &AnyJsxElement) -> bool {
+    element
+        .find_attribute_by_name("contentEditable")
+        .and_then(|attribute| attribute.as_static_value())
+        .and_then(|value| value.as_string_constant().map(|value| value == "true"))
+        .unwrap_or_default()
+}
diff --git a/crates/biome_js_analyze/src/options.rs b/crates/biome_js_analyze/src/options.rs
index 61b3ee5aef01..716a9a3c3ad1 100644
--- a/crates/biome_js_analyze/src/options.rs
+++ b/crates/biome_js_analyze/src/options.rs
@@ -160,6 +160,7 @@ pub type NoNodejsModules =
     <lint::correctness::no_nodejs_modules::NoNodejsModules as biome_analyze::Rule>::Options;
 pub type NoNonNullAssertion =
     <lint::style::no_non_null_assertion::NoNonNullAssertion as biome_analyze::Rule>::Options;
+pub type NoNoninteractiveElementInteractions = < lint :: nursery :: no_noninteractive_element_interactions :: NoNoninteractiveElementInteractions as biome_analyze :: Rule > :: Options ;
 pub type NoNoninteractiveElementToInteractiveRole = < lint :: a11y :: no_noninteractive_element_to_interactive_role :: NoNoninteractiveElementToInteractiveRole as biome_analyze :: Rule > :: Options ;
 pub type NoNoninteractiveTabindex = < lint :: a11y :: no_noninteractive_tabindex :: NoNoninteractiveTabindex as biome_analyze :: Rule > :: Options ;
 pub type NoNonoctalDecimalEscape = < lint :: correctness :: no_nonoctal_decimal_escape :: NoNonoctalDecimalEscape as biome_analyze :: Rule > :: Options ;
diff --git a/crates/biome_js_syntax/Cargo.toml b/crates/biome_js_syntax/Cargo.toml
index 1834edbe2ad7..c9c9f2e9272d 100644
--- a/crates/biome_js_syntax/Cargo.toml
+++ b/crates/biome_js_syntax/Cargo.toml
@@ -11,12 +11,13 @@ repository.workspace = true
 version              = "0.5.7"
 
 [dependencies]
-biome_aria        = { workspace = true }
-biome_rowan       = { workspace = true, features = ["serde"] }
-biome_string_case = { workspace = true }
-enumflags2        = { workspace = true }
-schemars          = { workspace = true, optional = true }
-serde             = { workspace = true, features = ["derive"] }
+biome_aria          = { workspace = true }
+biome_aria_metadata = { workspace = true }
+biome_rowan         = { workspace = true, features = ["serde"] }
+biome_string_case   = { workspace = true }
+enumflags2          = { workspace = true }
+schemars            = { workspace = true, optional = true }
+serde               = { workspace = true, features = ["derive"] }
 
 [dev-dependencies]
 biome_js_factory = { path = "../biome_js_factory" }
diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
index 39ea253f027c..87a41dd8481d 100644
--- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts
+++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
@@ -1298,6 +1298,10 @@ export interface Nursery {
 	 * Disallow nested ternary expressions.
 	 */
 	noNestedTernary?: RuleConfiguration_for_Null;
+	/**
+	 * Disallow use event handlers on non-interactive elements.
+	 */
+	noNoninteractiveElementInteractions?: RuleConfiguration_for_Null;
 	/**
 	 * Disallow octal escape sequences in string literals
 	 */
@@ -3112,6 +3116,7 @@ export type Category =
 	| "lint/nursery/noMissingGenericFamilyKeyword"
 	| "lint/nursery/noMissingVarFunction"
 	| "lint/nursery/noNestedTernary"
+	| "lint/nursery/noNoninteractiveElementInteractions"
 	| "lint/nursery/noOctalEscape"
 	| "lint/nursery/noProcessEnv"
 	| "lint/nursery/noProcessGlobal"
diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json
index b86d69556655..8b1a6b59d1b3 100644
--- a/packages/@biomejs/biome/configuration_schema.json
+++ b/packages/@biomejs/biome/configuration_schema.json
@@ -2316,6 +2316,13 @@
 						{ "type": "null" }
 					]
 				},
+				"noNoninteractiveElementInteractions": {
+					"description": "Disallow use event handlers on non-interactive elements.",
+					"anyOf": [
+						{ "$ref": "#/definitions/RuleConfiguration" },
+						{ "type": "null" }
+					]
+				},
 				"noOctalEscape": {
 					"description": "Disallow octal escape sequences in string literals",
 					"anyOf": [


Test patch:
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx
new file mode 100644
index 000000000000..cd94da2ad4b5
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx
@@ -0,0 +1,90 @@
+<>
+    <div onClick={() => { }} />
+    <main onClick={() => void 0} />
+    <article onClick={() => { }} />
+    <aside onClick={() => { }} />
+    <blockquote onClick={() => { }} />
+    <body onClick={() => { }} />
+    <br onClick={() => { }} />
+    <caption onClick={() => { }} />
+    <dd onClick={() => { }} />
+    <details onClick={() => { }} />
+    <dfn onClick={() => { }} />
+    <dl onClick={() => { }} />
+    <dir onClick={() => { }} />
+    <dt onClick={() => { }} />
+    <fieldset onClick={() => { }} />
+    <figcaption onClick={() => { }} />
+    <figure onClick={() => { }} />
+    <footer onClick={() => { }} />
+    <form onClick={() => { }} />
+    <frame onClick={() => { }} />
+    <h1 onClick={() => { }} />
+    <h2 onClick={() => { }} />
+    <h3 onClick={() => { }} />
+    <h4 onClick={() => { }} />
+    <h5 onClick={() => { }} />
+    <h6 onClick={() => { }} />
+    <iframe onClick={() => { }} />
+    <img onClick={() => { }} />
+    <label onClick={() => { }} />
+    <legend onClick={() => { }} />
+    <li onClick={() => { }} />
+    <mark onClick={() => { }} />
+    <marquee onClick={() => { }} />
+    <menu onClick={() => { }} />
+    <meter onClick={() => { }} />
+    <nav onClick={() => { }} />
+    <ol onClick={() => { }} />
+    <optgroup onClick={() => { }} />
+    <output onClick={() => { }} />
+    <p onClick={() => { }} />
+    <pre onClick={() => { }} />
+    <progress onClick={() => { }} />
+    <ruby onClick={() => { }} />
+    <section onClick={() => { }} aria-label="Aardvark" />
+    <section onClick={() => { }} aria-labelledby="js_1" />
+    <table onClick={() => { }} />
+    <tbody onClick={() => { }} />
+    <td onClick={() => { }} />
+    <tfoot onClick={() => { }} />
+    <thead onClick={() => { }} />
+    <time onClick={() => { }} />
+    <ul onClick={() => { }} />
+    <ul contentEditable="false" onClick={() => { }} />
+    <div role="alert" onClick={() => { }} />
+    <div role="alertdialog" onClick={() => { }} />
+    <div role="application" onClick={() => { }} />
+    <div role="banner" onClick={() => { }} />
+    <div role="cell" onClick={() => { }} />
+    <div role="complementary" onClick={() => { }} />
+    <div role="contentinfo" onClick={() => { }} />
+    <div role="definition" onClick={() => { }} />
+    <div role="dialog" onClick={() => { }} />
+    <div role="directory" onClick={() => { }} />
+    <div role="document" onClick={() => { }} />
+    <div role="feed" onClick={() => { }} />
+    <div role="figure" onClick={() => { }} />
+    <div role="form" onClick={() => { }} />
+    <div role="group" onClick={() => { }} />
+    <div role="heading" onClick={() => { }} />
+    <div role="img" onClick={() => { }} />
+    <div role="list" onClick={() => { }} />
+    <div role="listitem" onClick={() => { }} />
+    <div role="log" onClick={() => { }} />
+    <div role="main" onClick={() => { }} />
+    <div role="marquee" onClick={() => { }} />
+    <div role="math" onClick={() => { }} />
+    <div role="navigation" onClick={() => { }} />
+    <div role="note" onClick={() => { }} />
+    <div role="region" onClick={() => { }} />
+    <div role="rowgroup" onClick={() => { }} />
+    <div role="search" onClick={() => { }} />
+    <div role="status" onClick={() => { }} />
+    <div role="table" onClick={() => { }} />
+    <div role="tabpanel" onClick={() => { }} />
+    <div role="term" onClick={() => { }} />
+    <div role="timer" onClick={() => { }} />
+    <div role="tooltip" onClick={() => { }} />
+	  <div role="progressbar" onClick={() => { }} />
+</>
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx.snap b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx.snap
new file mode 100644
index 000000000000..eb382a467b4c
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/invalid.jsx.snap
@@ -0,0 +1,1578 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalid.jsx
+snapshot_kind: text
+---
+# Input
+```jsx
+<>
+    <div onClick={() => { }} />
+    <main onClick={() => void 0} />
+    <article onClick={() => { }} />
+    <aside onClick={() => { }} />
+    <blockquote onClick={() => { }} />
+    <body onClick={() => { }} />
+    <br onClick={() => { }} />
+    <caption onClick={() => { }} />
+    <dd onClick={() => { }} />
+    <details onClick={() => { }} />
+    <dfn onClick={() => { }} />
+    <dl onClick={() => { }} />
+    <dir onClick={() => { }} />
+    <dt onClick={() => { }} />
+    <fieldset onClick={() => { }} />
+    <figcaption onClick={() => { }} />
+    <figure onClick={() => { }} />
+    <footer onClick={() => { }} />
+    <form onClick={() => { }} />
+    <frame onClick={() => { }} />
+    <h1 onClick={() => { }} />
+    <h2 onClick={() => { }} />
+    <h3 onClick={() => { }} />
+    <h4 onClick={() => { }} />
+    <h5 onClick={() => { }} />
+    <h6 onClick={() => { }} />
+    <iframe onClick={() => { }} />
+    <img onClick={() => { }} />
+    <label onClick={() => { }} />
+    <legend onClick={() => { }} />
+    <li onClick={() => { }} />
+    <mark onClick={() => { }} />
+    <marquee onClick={() => { }} />
+    <menu onClick={() => { }} />
+    <meter onClick={() => { }} />
+    <nav onClick={() => { }} />
+    <ol onClick={() => { }} />
+    <optgroup onClick={() => { }} />
+    <output onClick={() => { }} />
+    <p onClick={() => { }} />
+    <pre onClick={() => { }} />
+    <progress onClick={() => { }} />
+    <ruby onClick={() => { }} />
+    <section onClick={() => { }} aria-label="Aardvark" />
+    <section onClick={() => { }} aria-labelledby="js_1" />
+    <table onClick={() => { }} />
+    <tbody onClick={() => { }} />
+    <td onClick={() => { }} />
+    <tfoot onClick={() => { }} />
+    <thead onClick={() => { }} />
+    <time onClick={() => { }} />
+    <ul onClick={() => { }} />
+    <ul contentEditable="false" onClick={() => { }} />
+    <div role="alert" onClick={() => { }} />
+    <div role="alertdialog" onClick={() => { }} />
+    <div role="application" onClick={() => { }} />
+    <div role="banner" onClick={() => { }} />
+    <div role="cell" onClick={() => { }} />
+    <div role="complementary" onClick={() => { }} />
+    <div role="contentinfo" onClick={() => { }} />
+    <div role="definition" onClick={() => { }} />
+    <div role="dialog" onClick={() => { }} />
+    <div role="directory" onClick={() => { }} />
+    <div role="document" onClick={() => { }} />
+    <div role="feed" onClick={() => { }} />
+    <div role="figure" onClick={() => { }} />
+    <div role="form" onClick={() => { }} />
+    <div role="group" onClick={() => { }} />
+    <div role="heading" onClick={() => { }} />
+    <div role="img" onClick={() => { }} />
+    <div role="list" onClick={() => { }} />
+    <div role="listitem" onClick={() => { }} />
+    <div role="log" onClick={() => { }} />
+    <div role="main" onClick={() => { }} />
+    <div role="marquee" onClick={() => { }} />
+    <div role="math" onClick={() => { }} />
+    <div role="navigation" onClick={() => { }} />
+    <div role="note" onClick={() => { }} />
+    <div role="region" onClick={() => { }} />
+    <div role="rowgroup" onClick={() => { }} />
+    <div role="search" onClick={() => { }} />
+    <div role="status" onClick={() => { }} />
+    <div role="table" onClick={() => { }} />
+    <div role="tabpanel" onClick={() => { }} />
+    <div role="term" onClick={() => { }} />
+    <div role="timer" onClick={() => { }} />
+    <div role="tooltip" onClick={() => { }} />
+	  <div role="progressbar" onClick={() => { }} />
+</>
+
+```
+
+# Diagnostics
+```
+invalid.jsx:2:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    1 │ <>
+  > 2 │     <div onClick={() => { }} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    3 │     <main onClick={() => void 0} />
+    4 │     <article onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:3:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    1 │ <>
+    2 │     <div onClick={() => { }} />
+  > 3 │     <main onClick={() => void 0} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    4 │     <article onClick={() => { }} />
+    5 │     <aside onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:4:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    2 │     <div onClick={() => { }} />
+    3 │     <main onClick={() => void 0} />
+  > 4 │     <article onClick={() => { }} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    5 │     <aside onClick={() => { }} />
+    6 │     <blockquote onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:5:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    3 │     <main onClick={() => void 0} />
+    4 │     <article onClick={() => { }} />
+  > 5 │     <aside onClick={() => { }} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    6 │     <blockquote onClick={() => { }} />
+    7 │     <body onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:6:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    4 │     <article onClick={() => { }} />
+    5 │     <aside onClick={() => { }} />
+  > 6 │     <blockquote onClick={() => { }} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    7 │     <body onClick={() => { }} />
+    8 │     <br onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:7:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    5 │     <aside onClick={() => { }} />
+    6 │     <blockquote onClick={() => { }} />
+  > 7 │     <body onClick={() => { }} />
+      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    8 │     <br onClick={() => { }} />
+    9 │     <caption onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:8:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+     6 │     <blockquote onClick={() => { }} />
+     7 │     <body onClick={() => { }} />
+   > 8 │     <br onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+     9 │     <caption onClick={() => { }} />
+    10 │     <dd onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:9:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+     7 │     <body onClick={() => { }} />
+     8 │     <br onClick={() => { }} />
+   > 9 │     <caption onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    10 │     <dd onClick={() => { }} />
+    11 │     <details onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:10:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+     8 │     <br onClick={() => { }} />
+     9 │     <caption onClick={() => { }} />
+  > 10 │     <dd onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    11 │     <details onClick={() => { }} />
+    12 │     <dfn onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:11:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+     9 │     <caption onClick={() => { }} />
+    10 │     <dd onClick={() => { }} />
+  > 11 │     <details onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    12 │     <dfn onClick={() => { }} />
+    13 │     <dl onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:12:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    10 │     <dd onClick={() => { }} />
+    11 │     <details onClick={() => { }} />
+  > 12 │     <dfn onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    13 │     <dl onClick={() => { }} />
+    14 │     <dir onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:14:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    12 │     <dfn onClick={() => { }} />
+    13 │     <dl onClick={() => { }} />
+  > 14 │     <dir onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    15 │     <dt onClick={() => { }} />
+    16 │     <fieldset onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:15:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    13 │     <dl onClick={() => { }} />
+    14 │     <dir onClick={() => { }} />
+  > 15 │     <dt onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    16 │     <fieldset onClick={() => { }} />
+    17 │     <figcaption onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:16:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    14 │     <dir onClick={() => { }} />
+    15 │     <dt onClick={() => { }} />
+  > 16 │     <fieldset onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    17 │     <figcaption onClick={() => { }} />
+    18 │     <figure onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:17:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    15 │     <dt onClick={() => { }} />
+    16 │     <fieldset onClick={() => { }} />
+  > 17 │     <figcaption onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    18 │     <figure onClick={() => { }} />
+    19 │     <footer onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:18:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    16 │     <fieldset onClick={() => { }} />
+    17 │     <figcaption onClick={() => { }} />
+  > 18 │     <figure onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    19 │     <footer onClick={() => { }} />
+    20 │     <form onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:19:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    17 │     <figcaption onClick={() => { }} />
+    18 │     <figure onClick={() => { }} />
+  > 19 │     <footer onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    20 │     <form onClick={() => { }} />
+    21 │     <frame onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:20:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    18 │     <figure onClick={() => { }} />
+    19 │     <footer onClick={() => { }} />
+  > 20 │     <form onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    21 │     <frame onClick={() => { }} />
+    22 │     <h1 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:21:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    19 │     <footer onClick={() => { }} />
+    20 │     <form onClick={() => { }} />
+  > 21 │     <frame onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    22 │     <h1 onClick={() => { }} />
+    23 │     <h2 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:22:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    20 │     <form onClick={() => { }} />
+    21 │     <frame onClick={() => { }} />
+  > 22 │     <h1 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    23 │     <h2 onClick={() => { }} />
+    24 │     <h3 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:23:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    21 │     <frame onClick={() => { }} />
+    22 │     <h1 onClick={() => { }} />
+  > 23 │     <h2 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    24 │     <h3 onClick={() => { }} />
+    25 │     <h4 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:24:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    22 │     <h1 onClick={() => { }} />
+    23 │     <h2 onClick={() => { }} />
+  > 24 │     <h3 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    25 │     <h4 onClick={() => { }} />
+    26 │     <h5 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:25:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    23 │     <h2 onClick={() => { }} />
+    24 │     <h3 onClick={() => { }} />
+  > 25 │     <h4 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    26 │     <h5 onClick={() => { }} />
+    27 │     <h6 onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:26:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    24 │     <h3 onClick={() => { }} />
+    25 │     <h4 onClick={() => { }} />
+  > 26 │     <h5 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    27 │     <h6 onClick={() => { }} />
+    28 │     <iframe onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:27:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    25 │     <h4 onClick={() => { }} />
+    26 │     <h5 onClick={() => { }} />
+  > 27 │     <h6 onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    28 │     <iframe onClick={() => { }} />
+    29 │     <img onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:28:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    26 │     <h5 onClick={() => { }} />
+    27 │     <h6 onClick={() => { }} />
+  > 28 │     <iframe onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    29 │     <img onClick={() => { }} />
+    30 │     <label onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:29:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    27 │     <h6 onClick={() => { }} />
+    28 │     <iframe onClick={() => { }} />
+  > 29 │     <img onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    30 │     <label onClick={() => { }} />
+    31 │     <legend onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:30:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    28 │     <iframe onClick={() => { }} />
+    29 │     <img onClick={() => { }} />
+  > 30 │     <label onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    31 │     <legend onClick={() => { }} />
+    32 │     <li onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:31:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    29 │     <img onClick={() => { }} />
+    30 │     <label onClick={() => { }} />
+  > 31 │     <legend onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    32 │     <li onClick={() => { }} />
+    33 │     <mark onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:32:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    30 │     <label onClick={() => { }} />
+    31 │     <legend onClick={() => { }} />
+  > 32 │     <li onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    33 │     <mark onClick={() => { }} />
+    34 │     <marquee onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:33:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    31 │     <legend onClick={() => { }} />
+    32 │     <li onClick={() => { }} />
+  > 33 │     <mark onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    34 │     <marquee onClick={() => { }} />
+    35 │     <menu onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:34:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    32 │     <li onClick={() => { }} />
+    33 │     <mark onClick={() => { }} />
+  > 34 │     <marquee onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    35 │     <menu onClick={() => { }} />
+    36 │     <meter onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:35:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    33 │     <mark onClick={() => { }} />
+    34 │     <marquee onClick={() => { }} />
+  > 35 │     <menu onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    36 │     <meter onClick={() => { }} />
+    37 │     <nav onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:36:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    34 │     <marquee onClick={() => { }} />
+    35 │     <menu onClick={() => { }} />
+  > 36 │     <meter onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    37 │     <nav onClick={() => { }} />
+    38 │     <ol onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:37:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    35 │     <menu onClick={() => { }} />
+    36 │     <meter onClick={() => { }} />
+  > 37 │     <nav onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    38 │     <ol onClick={() => { }} />
+    39 │     <optgroup onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:38:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    36 │     <meter onClick={() => { }} />
+    37 │     <nav onClick={() => { }} />
+  > 38 │     <ol onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    39 │     <optgroup onClick={() => { }} />
+    40 │     <output onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:39:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    37 │     <nav onClick={() => { }} />
+    38 │     <ol onClick={() => { }} />
+  > 39 │     <optgroup onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    40 │     <output onClick={() => { }} />
+    41 │     <p onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:40:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    38 │     <ol onClick={() => { }} />
+    39 │     <optgroup onClick={() => { }} />
+  > 40 │     <output onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    41 │     <p onClick={() => { }} />
+    42 │     <pre onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:41:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    39 │     <optgroup onClick={() => { }} />
+    40 │     <output onClick={() => { }} />
+  > 41 │     <p onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^
+    42 │     <pre onClick={() => { }} />
+    43 │     <progress onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:42:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    40 │     <output onClick={() => { }} />
+    41 │     <p onClick={() => { }} />
+  > 42 │     <pre onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    43 │     <progress onClick={() => { }} />
+    44 │     <ruby onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:43:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    41 │     <p onClick={() => { }} />
+    42 │     <pre onClick={() => { }} />
+  > 43 │     <progress onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    44 │     <ruby onClick={() => { }} />
+    45 │     <section onClick={() => { }} aria-label="Aardvark" />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:44:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    42 │     <pre onClick={() => { }} />
+    43 │     <progress onClick={() => { }} />
+  > 44 │     <ruby onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    45 │     <section onClick={() => { }} aria-label="Aardvark" />
+    46 │     <section onClick={() => { }} aria-labelledby="js_1" />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:45:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    43 │     <progress onClick={() => { }} />
+    44 │     <ruby onClick={() => { }} />
+  > 45 │     <section onClick={() => { }} aria-label="Aardvark" />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    46 │     <section onClick={() => { }} aria-labelledby="js_1" />
+    47 │     <table onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:46:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    44 │     <ruby onClick={() => { }} />
+    45 │     <section onClick={() => { }} aria-label="Aardvark" />
+  > 46 │     <section onClick={() => { }} aria-labelledby="js_1" />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    47 │     <table onClick={() => { }} />
+    48 │     <tbody onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:47:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    45 │     <section onClick={() => { }} aria-label="Aardvark" />
+    46 │     <section onClick={() => { }} aria-labelledby="js_1" />
+  > 47 │     <table onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    48 │     <tbody onClick={() => { }} />
+    49 │     <td onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:48:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    46 │     <section onClick={() => { }} aria-labelledby="js_1" />
+    47 │     <table onClick={() => { }} />
+  > 48 │     <tbody onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    49 │     <td onClick={() => { }} />
+    50 │     <tfoot onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:49:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    47 │     <table onClick={() => { }} />
+    48 │     <tbody onClick={() => { }} />
+  > 49 │     <td onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    50 │     <tfoot onClick={() => { }} />
+    51 │     <thead onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:50:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    48 │     <tbody onClick={() => { }} />
+    49 │     <td onClick={() => { }} />
+  > 50 │     <tfoot onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    51 │     <thead onClick={() => { }} />
+    52 │     <time onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:51:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    49 │     <td onClick={() => { }} />
+    50 │     <tfoot onClick={() => { }} />
+  > 51 │     <thead onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    52 │     <time onClick={() => { }} />
+    53 │     <ul onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:52:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    50 │     <tfoot onClick={() => { }} />
+    51 │     <thead onClick={() => { }} />
+  > 52 │     <time onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    53 │     <ul onClick={() => { }} />
+    54 │     <ul contentEditable="false" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:53:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    51 │     <thead onClick={() => { }} />
+    52 │     <time onClick={() => { }} />
+  > 53 │     <ul onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+    54 │     <ul contentEditable="false" onClick={() => { }} />
+    55 │     <div role="alert" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:54:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    52 │     <time onClick={() => { }} />
+    53 │     <ul onClick={() => { }} />
+  > 54 │     <ul contentEditable="false" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    55 │     <div role="alert" onClick={() => { }} />
+    56 │     <div role="alertdialog" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:55:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    53 │     <ul onClick={() => { }} />
+    54 │     <ul contentEditable="false" onClick={() => { }} />
+  > 55 │     <div role="alert" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    56 │     <div role="alertdialog" onClick={() => { }} />
+    57 │     <div role="application" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:56:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    54 │     <ul contentEditable="false" onClick={() => { }} />
+    55 │     <div role="alert" onClick={() => { }} />
+  > 56 │     <div role="alertdialog" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    57 │     <div role="application" onClick={() => { }} />
+    58 │     <div role="banner" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:57:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    55 │     <div role="alert" onClick={() => { }} />
+    56 │     <div role="alertdialog" onClick={() => { }} />
+  > 57 │     <div role="application" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    58 │     <div role="banner" onClick={() => { }} />
+    59 │     <div role="cell" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:58:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    56 │     <div role="alertdialog" onClick={() => { }} />
+    57 │     <div role="application" onClick={() => { }} />
+  > 58 │     <div role="banner" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    59 │     <div role="cell" onClick={() => { }} />
+    60 │     <div role="complementary" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:59:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    57 │     <div role="application" onClick={() => { }} />
+    58 │     <div role="banner" onClick={() => { }} />
+  > 59 │     <div role="cell" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    60 │     <div role="complementary" onClick={() => { }} />
+    61 │     <div role="contentinfo" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:60:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    58 │     <div role="banner" onClick={() => { }} />
+    59 │     <div role="cell" onClick={() => { }} />
+  > 60 │     <div role="complementary" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    61 │     <div role="contentinfo" onClick={() => { }} />
+    62 │     <div role="definition" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:61:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    59 │     <div role="cell" onClick={() => { }} />
+    60 │     <div role="complementary" onClick={() => { }} />
+  > 61 │     <div role="contentinfo" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    62 │     <div role="definition" onClick={() => { }} />
+    63 │     <div role="dialog" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:62:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    60 │     <div role="complementary" onClick={() => { }} />
+    61 │     <div role="contentinfo" onClick={() => { }} />
+  > 62 │     <div role="definition" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    63 │     <div role="dialog" onClick={() => { }} />
+    64 │     <div role="directory" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:63:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    61 │     <div role="contentinfo" onClick={() => { }} />
+    62 │     <div role="definition" onClick={() => { }} />
+  > 63 │     <div role="dialog" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    64 │     <div role="directory" onClick={() => { }} />
+    65 │     <div role="document" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:64:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    62 │     <div role="definition" onClick={() => { }} />
+    63 │     <div role="dialog" onClick={() => { }} />
+  > 64 │     <div role="directory" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    65 │     <div role="document" onClick={() => { }} />
+    66 │     <div role="feed" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:65:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    63 │     <div role="dialog" onClick={() => { }} />
+    64 │     <div role="directory" onClick={() => { }} />
+  > 65 │     <div role="document" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    66 │     <div role="feed" onClick={() => { }} />
+    67 │     <div role="figure" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:66:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    64 │     <div role="directory" onClick={() => { }} />
+    65 │     <div role="document" onClick={() => { }} />
+  > 66 │     <div role="feed" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    67 │     <div role="figure" onClick={() => { }} />
+    68 │     <div role="form" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:67:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    65 │     <div role="document" onClick={() => { }} />
+    66 │     <div role="feed" onClick={() => { }} />
+  > 67 │     <div role="figure" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    68 │     <div role="form" onClick={() => { }} />
+    69 │     <div role="group" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:68:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    66 │     <div role="feed" onClick={() => { }} />
+    67 │     <div role="figure" onClick={() => { }} />
+  > 68 │     <div role="form" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    69 │     <div role="group" onClick={() => { }} />
+    70 │     <div role="heading" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:69:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    67 │     <div role="figure" onClick={() => { }} />
+    68 │     <div role="form" onClick={() => { }} />
+  > 69 │     <div role="group" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    70 │     <div role="heading" onClick={() => { }} />
+    71 │     <div role="img" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:70:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    68 │     <div role="form" onClick={() => { }} />
+    69 │     <div role="group" onClick={() => { }} />
+  > 70 │     <div role="heading" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    71 │     <div role="img" onClick={() => { }} />
+    72 │     <div role="list" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:71:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    69 │     <div role="group" onClick={() => { }} />
+    70 │     <div role="heading" onClick={() => { }} />
+  > 71 │     <div role="img" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    72 │     <div role="list" onClick={() => { }} />
+    73 │     <div role="listitem" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:72:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    70 │     <div role="heading" onClick={() => { }} />
+    71 │     <div role="img" onClick={() => { }} />
+  > 72 │     <div role="list" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    73 │     <div role="listitem" onClick={() => { }} />
+    74 │     <div role="log" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:73:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    71 │     <div role="img" onClick={() => { }} />
+    72 │     <div role="list" onClick={() => { }} />
+  > 73 │     <div role="listitem" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    74 │     <div role="log" onClick={() => { }} />
+    75 │     <div role="main" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:74:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    72 │     <div role="list" onClick={() => { }} />
+    73 │     <div role="listitem" onClick={() => { }} />
+  > 74 │     <div role="log" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    75 │     <div role="main" onClick={() => { }} />
+    76 │     <div role="marquee" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:75:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    73 │     <div role="listitem" onClick={() => { }} />
+    74 │     <div role="log" onClick={() => { }} />
+  > 75 │     <div role="main" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    76 │     <div role="marquee" onClick={() => { }} />
+    77 │     <div role="math" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:76:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    74 │     <div role="log" onClick={() => { }} />
+    75 │     <div role="main" onClick={() => { }} />
+  > 76 │     <div role="marquee" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    77 │     <div role="math" onClick={() => { }} />
+    78 │     <div role="navigation" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:77:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    75 │     <div role="main" onClick={() => { }} />
+    76 │     <div role="marquee" onClick={() => { }} />
+  > 77 │     <div role="math" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    78 │     <div role="navigation" onClick={() => { }} />
+    79 │     <div role="note" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:78:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    76 │     <div role="marquee" onClick={() => { }} />
+    77 │     <div role="math" onClick={() => { }} />
+  > 78 │     <div role="navigation" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    79 │     <div role="note" onClick={() => { }} />
+    80 │     <div role="region" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:79:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    77 │     <div role="math" onClick={() => { }} />
+    78 │     <div role="navigation" onClick={() => { }} />
+  > 79 │     <div role="note" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    80 │     <div role="region" onClick={() => { }} />
+    81 │     <div role="rowgroup" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:80:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    78 │     <div role="navigation" onClick={() => { }} />
+    79 │     <div role="note" onClick={() => { }} />
+  > 80 │     <div role="region" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    81 │     <div role="rowgroup" onClick={() => { }} />
+    82 │     <div role="search" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:81:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    79 │     <div role="note" onClick={() => { }} />
+    80 │     <div role="region" onClick={() => { }} />
+  > 81 │     <div role="rowgroup" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    82 │     <div role="search" onClick={() => { }} />
+    83 │     <div role="status" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:82:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    80 │     <div role="region" onClick={() => { }} />
+    81 │     <div role="rowgroup" onClick={() => { }} />
+  > 82 │     <div role="search" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    83 │     <div role="status" onClick={() => { }} />
+    84 │     <div role="table" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:83:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    81 │     <div role="rowgroup" onClick={() => { }} />
+    82 │     <div role="search" onClick={() => { }} />
+  > 83 │     <div role="status" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    84 │     <div role="table" onClick={() => { }} />
+    85 │     <div role="tabpanel" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:84:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    82 │     <div role="search" onClick={() => { }} />
+    83 │     <div role="status" onClick={() => { }} />
+  > 84 │     <div role="table" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    85 │     <div role="tabpanel" onClick={() => { }} />
+    86 │     <div role="term" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:85:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    83 │     <div role="status" onClick={() => { }} />
+    84 │     <div role="table" onClick={() => { }} />
+  > 85 │     <div role="tabpanel" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    86 │     <div role="term" onClick={() => { }} />
+    87 │     <div role="timer" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:86:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    84 │     <div role="table" onClick={() => { }} />
+    85 │     <div role="tabpanel" onClick={() => { }} />
+  > 86 │     <div role="term" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    87 │     <div role="timer" onClick={() => { }} />
+    88 │     <div role="tooltip" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:87:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    85 │     <div role="tabpanel" onClick={() => { }} />
+    86 │     <div role="term" onClick={() => { }} />
+  > 87 │     <div role="timer" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    88 │     <div role="tooltip" onClick={() => { }} />
+    89 │ 	  <div role="progressbar" onClick={() => { }} />
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:88:5 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    86 │     <div role="term" onClick={() => { }} />
+    87 │     <div role="timer" onClick={() => { }} />
+  > 88 │     <div role="tooltip" onClick={() => { }} />
+       │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    89 │ 	  <div role="progressbar" onClick={() => { }} />
+    90 │ </>
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
+
+```
+invalid.jsx:89:4 lint/nursery/noNoninteractiveElementInteractions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Non-interactive element should not have event handler.
+  
+    87 │     <div role="timer" onClick={() => { }} />
+    88 │     <div role="tooltip" onClick={() => { }} />
+  > 89 │ 	  <div role="progressbar" onClick={() => { }} />
+       │ 	  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    90 │ </>
+    91 │ 
+  
+  i Consider replace semantically interactive element like <button/> or <a href/>.
+  
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx
new file mode 100644
index 000000000000..84eb4fec4642
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx
@@ -0,0 +1,50 @@
+<>
+    {/* Custom Components */}
+    <TestComponent onClick={doFoo} />
+    <Button onClick={doFoo} />
+    <Image onClick={() => void 0} />
+
+    {/* Input element */}
+    <input onClick={() => void 0} />
+    <input type="button" onClick={() => void 0} />
+    <input type="checkbox" onClick={() => void 0} />
+    <input type="color" onClick={() => void 0} />
+
+    {/* Interactive element */}
+    <a onClick={() => void 0} />
+    <area onClick={() => { }} />
+    <button onClick={() => void 0} />
+    <menuitem onClick={() => { }} />
+    <option onClick={() => void 0} className="foo" />
+    <select onClick={() => void 0} className="foo" />
+    <textarea onClick={() => void 0} className="foo" />
+    <tr onClick={() => { }} />
+
+    {/* Element attributed with an interactive role*/}
+    <div role="button" onClick={() => { }} />
+    <div role="checkbox" onClick={() => { }} />
+    <div role="combobox" onClick={() => { }} />
+    <div role="gridcell" onClick={() => { }} />
+    <div role="link" onClick={() => { }} />
+    <div role="listbox" onClick={() => { }} />
+    <div role="menuitem" onClick={() => { }} />
+    <div role="menuitemcheckbox" onClick={() => { }} />
+    <div role="menuitemradio" onClick={() => { }} />
+    <div role="option" onClick={() => { }} />
+    <div role="radio" onClick={() => { }} />
+    <div role="row" onClick={() => { }} />
+    <div role="scrollbar" onClick={() => { }} />
+    <div role="searchbox" onClick={() => { }} />
+    <div role="slider" onClick={() => { }} />
+    <div role="spinbutton" onClick={() => { }} />
+    <div role="switch" onClick={() => { }} />
+    <div role="tab" onClick={() => { }} />
+    <div role="textbox" onClick={() => { }} />
+
+    {/* Presentation role */}
+    <div role="presentation" onClick={() => { }} />
+
+		<div onClick={() => {}} aria-hidden />
+		<div onClick={() => {}} aria-hidden="true" />
+
+</>
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx.snap b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx.snap
new file mode 100644
index 000000000000..c505af534095
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noNoninteractiveElementInteractions/valid.jsx.snap
@@ -0,0 +1,59 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: valid.jsx
+snapshot_kind: text
+---
+# Input
+```jsx
+<>
+    {/* Custom Components */}
+    <TestComponent onClick={doFoo} />
+    <Button onClick={doFoo} />
+    <Image onClick={() => void 0} />
+
+    {/* Input element */}
+    <input onClick={() => void 0} />
+    <input type="button" onClick={() => void 0} />
+    <input type="checkbox" onClick={() => void 0} />
+    <input type="color" onClick={() => void 0} />
+
+    {/* Interactive element */}
+    <a onClick={() => void 0} />
+    <area onClick={() => { }} />
+    <button onClick={() => void 0} />
+    <menuitem onClick={() => { }} />
+    <option onClick={() => void 0} className="foo" />
+    <select onClick={() => void 0} className="foo" />
+    <textarea onClick={() => void 0} className="foo" />
+    <tr onClick={() => { }} />
+
+    {/* Element attributed with an interactive role*/}
+    <div role="button" onClick={() => { }} />
+    <div role="checkbox" onClick={() => { }} />
+    <div role="combobox" onClick={() => { }} />
+    <div role="gridcell" onClick={() => { }} />
+    <div role="link" onClick={() => { }} />
+    <div role="listbox" onClick={() => { }} />
+    <div role="menuitem" onClick={() => { }} />
+    <div role="menuitemcheckbox" onClick={() => { }} />
+    <div role="menuitemradio" onClick={() => { }} />
+    <div role="option" onClick={() => { }} />
+    <div role="radio" onClick={() => { }} />
+    <div role="row" onClick={() => { }} />
+    <div role="scrollbar" onClick={() => { }} />
+    <div role="searchbox" onClick={() => { }} />
+    <div role="slider" onClick={() => { }} />
+    <div role="spinbutton" onClick={() => { }} />
+    <div role="switch" onClick={() => { }} />
+    <div role="tab" onClick={() => { }} />
+    <div role="textbox" onClick={() => { }} />
+
+    {/* Presentation role */}
+    <div role="presentation" onClick={() => { }} />
+
+		<div onClick={() => {}} aria-hidden />
+		<div onClick={() => {}} aria-hidden="true" />
+
+</>
+
+```