Skip to content

feat(html_analyze): implement noNoninteractiveElementInteractions#10026

Merged
Netail merged 2 commits into
biomejs:nextfrom
Netail:feat/port-no-noninteractive-element-interactions
Apr 19, 2026
Merged

feat(html_analyze): implement noNoninteractiveElementInteractions#10026
Netail merged 2 commits into
biomejs:nextfrom
Netail:feat/port-no-noninteractive-element-interactions

Conversation

@Netail

@Netail Netail commented Apr 17, 2026

Copy link
Copy Markdown
Member

Summary

Port noNoninteractiveElementInteractions to the HTML analyzer

Related #8155

Test Plan

Added unit tests

Docs

@changeset-bot

changeset-bot Bot commented Apr 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 585fb00

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@biomejs/biome Minor
@biomejs/cli-win32-x64 Minor
@biomejs/cli-win32-arm64 Minor
@biomejs/cli-darwin-x64 Minor
@biomejs/cli-darwin-arm64 Minor
@biomejs/cli-linux-x64 Minor
@biomejs/cli-linux-arm64 Minor
@biomejs/cli-linux-x64-musl Minor
@biomejs/cli-linux-arm64-musl Minor
@biomejs/wasm-web Minor
@biomejs/wasm-bundler Minor
@biomejs/wasm-nodejs Minor
@biomejs/backend-jsonrpc Patch
@biomejs/js-api Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-Linter Area: linter A-Parser Area: parser L-JavaScript Language: JavaScript and super languages L-HTML Language: HTML and super languages labels Apr 17, 2026
@Netail Netail mentioned this pull request Apr 17, 2026
32 tasks
@Netail Netail marked this pull request as draft April 17, 2026 21:12
@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new HTML accessibility lint rule noNoninteractiveElementInteractions that flags event handlers on non-interactive elements and reports diagnostics with suggestions (e.g., button, a[href]). Adds is_content_editable helper and a Vue event-directive finder method on AnyHtmlTagElement. The rule ignores custom components, contenteditable="true", role="presentation", aria-hidden="true", and elements with interactive ARIA roles. Extensive test fixtures were added for HTML, Astro, Vue and Svelte. The JS analyzer rule’s control flow was tweaked for consistent reporting.

Possibly related PRs

Suggested reviewers

  • dyc3
  • ematipico
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: implementing the noNoninteractiveElementInteractions rule for the HTML analyser.
Description check ✅ Passed The description is directly related to the changeset, clearly stating the rule is being ported to the HTML analyser with unit tests added.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
crates/biome_html_analyze/src/a11y.rs (1)

186-195: Consider case-insensitive matching for contenteditable.

HTML attribute values are case-insensitive per spec. contenteditable="TRUE" or contenteditable="True" would currently return false. Consider using eq_ignore_ascii_case("true") for consistency with how other HTML attribute checks work in this module (e.g., attribute_value_equals_ignore_case).

That said, if you're intentionally mirroring the eslint-plugin-jsx-a11y behaviour exactly, this is fine as-is.

🔧 Optional fix for case-insensitivity
 pub(crate) fn is_content_editable(element: &AnyHtmlTagElement) -> bool {
     element
         .find_attribute_by_name("contenteditable")
-        .is_some_and(|attribute| is_strict_true_value(&attribute))
+        .is_some_and(|attribute| attribute_value_equals_ignore_case(&attribute, "true"))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_analyze/src/a11y.rs` around lines 186 - 195, The
is_content_editable function currently treats the contenteditable attribute
value case-sensitively; update its check in is_content_editable (which takes
&AnyHtmlTagElement) to perform a case-insensitive comparison (e.g., use
attribute_value_equals_ignore_case or call eq_ignore_ascii_case("true") on the
attribute value) so that values like "TRUE" or "True" return true; ensure you
still handle the attribute absence the same way (is_some_and(...)).
crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue (1)

1-44: Consider adding a contenteditable="true" test case.

The is_content_editable helper suppresses diagnostics for content-editable elements, but there's no valid test case demonstrating this. Adding one would improve coverage:

<div contenteditable="true" `@click`="() => { }"></div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue`
around lines 1 - 44, Add a valid test case demonstrating suppression for
content-editable elements by inserting a line with a contenteditable element
(e.g. <div contenteditable="true" `@click`="() => { }"></div>) into the existing
valid.vue tests so the is_content_editable branch is covered; place it near the
other valid div examples (e.g. alongside the presentation/aria-hidden cases) to
ensure the rule recognizes contenteditable elements as non-diagnostic.
crates/biome_html_syntax/src/element_ext.rs (1)

461-470: Tiny comment fix: directive syntax labels are swapped.

VueVOnShorthandDirective is @name, and VueDirective here is v-on:name (not :name / v-bind:name).

Suggested comment-only patch
-                    // :name="..."
+                    // `@name`="..."
                     AnyVueDirective::VueVOnShorthandDirective(d) => d
@@
-                    // v-bind:name="..."
+                    // v-on:name="..."
                     AnyVueDirective::VueDirective(d) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_syntax/src/element_ext.rs` around lines 461 - 470, The
inline comments labeling directive variants are swapped: update the comment
above AnyVueDirective::VueVOnShorthandDirective to indicate it matches the v-on
shorthand (e.g., "@name") and change the comment above
AnyVueDirective::VueDirective to indicate it matches the full v-on form (e.g.,
"v-on:name"); locate the matching match arm code around VueVOnShorthandDirective
and VueDirective in element_ext.rs and replace the incorrect ":name=\"...\" /
v-bind:name=\"...\"" comments with the correct "@name" and "v-on:name" labels
respectively.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`:
- Around line 15-17: The documentation comment in
no_noninteractive_element_interactions.rs incorrectly lists `<area>` as a
non-interactive element; update the doc comment (the triple-slash block above
the lint implementation in the no_noninteractive_element_interactions module) to
remove `<area>` from the example list so it matches the rule's fixtures and
behavior for allowed elements.

---

Nitpick comments:
In `@crates/biome_html_analyze/src/a11y.rs`:
- Around line 186-195: The is_content_editable function currently treats the
contenteditable attribute value case-sensitively; update its check in
is_content_editable (which takes &AnyHtmlTagElement) to perform a
case-insensitive comparison (e.g., use attribute_value_equals_ignore_case or
call eq_ignore_ascii_case("true") on the attribute value) so that values like
"TRUE" or "True" return true; ensure you still handle the attribute absence the
same way (is_some_and(...)).

In
`@crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue`:
- Around line 1-44: Add a valid test case demonstrating suppression for
content-editable elements by inserting a line with a contenteditable element
(e.g. <div contenteditable="true" `@click`="() => { }"></div>) into the existing
valid.vue tests so the is_content_editable branch is covered; place it near the
other valid div examples (e.g. alongside the presentation/aria-hidden cases) to
ensure the rule recognizes contenteditable elements as non-diagnostic.

In `@crates/biome_html_syntax/src/element_ext.rs`:
- Around line 461-470: The inline comments labeling directive variants are
swapped: update the comment above AnyVueDirective::VueVOnShorthandDirective to
indicate it matches the v-on shorthand (e.g., "@name") and change the comment
above AnyVueDirective::VueDirective to indicate it matches the full v-on form
(e.g., "v-on:name"); locate the matching match arm code around
VueVOnShorthandDirective and VueDirective in element_ext.rs and replace the
incorrect ":name=\"...\" / v-bind:name=\"...\"" comments with the correct
"@name" and "v-on:name" labels respectively.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac2ea570-a1c5-44d2-8464-e6412b0f3f55

📥 Commits

Reviewing files that changed from the base of the PR and between 3422d71 and e1280d3.

⛔ Files ignored due to path filters (8)
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (13)
  • .changeset/wicked-lions-brake.md
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs

@codspeed-hq

codspeed-hq Bot commented Apr 17, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 21%

❌ 4 regressed benchmarks
✅ 121 untouched benchmarks
⏩ 129 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
html_analyzer[real/wikipedia-fr-Guerre_de_Canudos.html] 1.1 s 1.4 s -21%
html_analyzer[real/wikipedia-Unix.html] 452.5 ms 555.2 ms -18.49%
html_analyzer[real/wikipedia-JavaScript.html] 548 ms 670.3 ms -18.25%
html_analyzer[index_1033418810622582172.html] 1 ms 1.2 ms -18.53%

Comparing Netail:feat/port-no-noninteractive-element-interactions (585fb00) with next (3422d71)

Open in CodSpeed

Footnotes

  1. 129 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Netail Netail force-pushed the feat/port-no-noninteractive-element-interactions branch from e1280d3 to 03c2def Compare April 17, 2026 22:26
@Netail Netail marked this pull request as ready for review April 17, 2026 22:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_html_syntax/src/element_ext.rs`:
- Around line 461-470: Update the two inline comments that are copy-pasted
incorrectly: where the match arm for AnyVueDirective::VueVOnShorthandDirective
currently has a comment saying `:name="..."` change it to `@name="..."`, and
where the match arm for AnyVueDirective::VueDirective (handling v-on style
directives) currently has a comment saying `v-bind:name="..."` change it to
`v-on:name="..."`; these comments are adjacent to the VueVOnShorthandDirective
and VueDirective match arms in element_ext.rs and should reflect event-handling
directives.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7d3be585-0c3b-495b-a683-a2f2d9cc6856

📥 Commits

Reviewing files that changed from the base of the PR and between e1280d3 and 03c2def.

⛔ Files ignored due to path filters (8)
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (15)
  • .changeset/major-bats-fail.md
  • .changeset/wicked-lions-brake.md
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
✅ Files skipped from review due to trivial changes (6)
  • .changeset/major-bats-fail.md
  • .changeset/wicked-lions-brake.md
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte
🚧 Files skipped from review as they are similar to previous changes (5)
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs

Comment thread crates/biome_html_syntax/src/element_ext.rs Outdated
@Netail Netail force-pushed the feat/port-no-noninteractive-element-interactions branch from 03c2def to 030207d Compare April 17, 2026 22:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`:
- Around line 122-124: The diagnostic note string inside the .note(markup! { ...
}) in no_noninteractive_element_interactions.rs has awkward grammar; update the
message to read "Consider replacing with a semantically interactive element like
"<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
Locate the .note(markup! { ... }) call that currently contains "Consider replace
semantically interactive element like ..." and replace that fragment with the
corrected "Consider replacing with a semantically interactive element like ..."
text.
- Around line 129-155: The INTERACTIVE_HANDLERS constant contains an invalid
HTML event name "ondoubleclick" that should be removed; update the slice in
no_noninteractive_element_interactions.rs to delete the "ondoubleclick" entry
(leave "ondblclick" intact) and run tests, and optionally consider whether to
separately add pointer/touch events in a different change if you intend to
support modern input handlers rather than developer-typo checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7f5767dc-b4f4-460f-86ad-dcd507b291eb

📥 Commits

Reviewing files that changed from the base of the PR and between 03c2def and 030207d.

⛔ Files ignored due to path filters (8)
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (15)
  • .changeset/major-bats-fail.md
  • .changeset/wicked-lions-brake.md
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue
  • crates/biome_html_syntax/src/element_ext.rs
  • crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
✅ Files skipped from review due to trivial changes (8)
  • .changeset/major-bats-fail.md
  • .changeset/wicked-lions-brake.md
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_to_interactive_role.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/valid.astro
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/vue/valid.vue
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/valid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/astro/invalid.astro
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/biome_html_analyze/src/a11y.rs
  • crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs
  • crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/invalid.svelte
  • crates/biome_html_syntax/src/element_ext.rs

Comment on lines +122 to +124
.note(markup! {
"Consider replace semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor grammar tweak in diagnostic message.

The note reads "Consider replace semantically" — should be "Consider replacing with a semantically".

Suggested fix
             .note(markup! {
-                "Consider replace semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
+                "Consider replacing with a semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
             })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.note(markup! {
"Consider replace semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
})
.note(markup! {
"Consider replacing with a semantically interactive element like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`
around lines 122 - 124, The diagnostic note string inside the .note(markup! {
... }) in no_noninteractive_element_interactions.rs has awkward grammar; update
the message to read "Consider replacing with a semantically interactive element
like "<Emphasis>"<button/>"</Emphasis>" or "<Emphasis>"<a href/>"</Emphasis>"."
Locate the .note(markup! { ... }) call that currently contains "Consider replace
semantically interactive element like ..." and replace that fragment with the
corrected "Consider replacing with a semantically interactive element like ..."
text.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as JS rule

Comment on lines +129 to +155
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",
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

What are all the standard HTML global event handler attributes?

💡 Result:

The standard HTML global event handler attributes are those available on all HTML elements as content attributes (and IDL attributes on elements, Document, and Window). They correspond to common DOM events and are prefixed with "on". According to MDN Web Docs (the most comprehensive and up-to-date list from authoritative sources tracking the HTML Living Standard), they include: onabort, onanimationcancel, onanimationend, onanimationiteration, onanimationstart, onauxclick, onbeforeinput, onbeforematch, onbeforetoggle, onblur, oncancel, oncanplay, oncanplaythrough, onchange, onclick, onclose, oncommand, oncontentvisibilityautostatechange, oncontextlost, oncontextmenu, oncontextrestored, oncopy, oncuechange, oncut, ondblclick, ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, onfocusin, onfocusout, onformdata, onfullscreenchange, onfullscreenerror, ongesturechange, ongestureend, ongesturestart, ongotpointercapture, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onload, onloadeddata, onloadedmetadata, onloadstart, onlostpointercapture, onmousedown, onmouseenter, onmouseleave, onmousemove, onmouseout, onmouseover, onmouseup, onmousewheel, onpaste, onpause, onplay, onplaying, onpointercancel, onpointerdown, onpointerenter, onpointerleave, onpointermove, onpointerout, onpointerover, onpointerrawupdate, onpointerup, onprogress, onratechange, onreset, onresize, onscroll, onsecuritypolicyviolation, onseeked, onseeking, onselect, onselectionchange, onselectstart, onslotchange, onstalled, onsubmit, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting, onwebkitanimationend, onwebkitanimationiteration, onwebkitanimationstart, onwebkittransitionend, onwheel, onwebkitmouseforcedown, onwebkitmouseforceup, onwebkitmouseforcewillbegin. The WHATWG HTML Living Standard (section 8.1.6.2) confirms these are the event handlers supported by all HTML elements as content attributes, with some additional Window-specific ones on body/frameset. MDN's list reflects the current standard as of 2026, including newer events like onbeforetoggle and oncontentvisibilityautostatechange. Note: While all "on*" attributes for known events are accepted on elements, only those corresponding to events that can fire on arbitrary elements are truly "global" in effect. Vendor-prefixed (webkit*) and deprecated (onkeypress) ones are included for completeness as they are standard global attributes.

Citations:


🏁 Script executed:

# First, let's understand the rule's purpose
cat -n crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs | head -150

Repository: biomejs/biome

Length of output: 6326


🏁 Script executed:

# Check if there are any comments or rationale around INTERACTIVE_HANDLERS
rg -A 5 -B 5 "INTERACTIVE_HANDLERS" crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs

Repository: biomejs/biome

Length of output: 564


🏁 Script executed:

# Look for test files related to this rule
fd "no_noninteractive_element_interactions" crates/biome_html_analyze/tests/

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Look for test files related to this rule
find crates/biome_html_analyze/tests -name "*no_noninteractive*" -type f

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if there are snapshot tests or fixtures
find crates/biome_html_analyze/tests -type d -name "no_noninteractive*"

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Search for any discussion or comments about ondoubleclick in the codebase
rg "ondoubleclick" --type-add "rust:*.rs" -B 3 -A 3

Repository: biomejs/biome

Length of output: 755


🏁 Script executed:

# Check git history or comments about why ondoubleclick might be there
rg "doubleclick" crates/ --type-add "rust:*.rs" -B 2 -A 2

Repository: biomejs/biome

Length of output: 557


🏁 Script executed:

# Check if there are similar rules in other linters (JS/TS)
find crates -name "*noninteractive*" -type f | head -20

Repository: biomejs/biome

Length of output: 909


🏁 Script executed:

# Look for any configuration or documentation about this rule
find . -name "*.md" -o -name "*.json" | xargs grep -l "noNoninteractiveElementInteractions" 2>/dev/null | head -5

Repository: biomejs/biome

Length of output: 143


🏁 Script executed:

# Check if the rule was recently added or modified with any commit message context
git log --oneline -n 50 -- crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs 2>/dev/null | head -10

Repository: biomejs/biome

Length of output: 132


🏁 Script executed:

# Check ESLint jsx-a11y plugin (often the source of accessibility rules) for comparison
# This will help understand if ondoubleclick is intentional
rg "ondoubleclick|onTouchStart|ontouchstart" --type-add "rust:*.rs" --type-add "ts:*.ts" --type-add "js:*.js" crates/ | head -20

Repository: biomejs/biome

Length of output: 1093


🏁 Script executed:

# Check the JS version of the same rule to see if it has different handlers
cat crates/biome_js_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs | grep -A 30 "INTERACTIVE_HANDLERS"

Repository: biomejs/biome

Length of output: 758


🏁 Script executed:

# Look for test specs for the HTML rule
find crates/biome_html_analyze/tests/specs -name "*noNoninteractive*" -o -name "*interactive*" | head -10

Repository: biomejs/biome

Length of output: 287


🏁 Script executed:

# Check the test specs for the HTML rule to understand intended behavior
ls -la crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/

Repository: biomejs/biome

Length of output: 604


🏁 Script executed:

# Read the test files to see if ondoubleclick is actually tested
cat crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/*.html 2>/dev/null | head -100

Repository: biomejs/biome

Length of output: 3981


🏁 Script executed:

# Check if there's a snapshot file
cat crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/*.snap 2>/dev/null | head -150

Repository: biomejs/biome

Length of output: 5357


🏁 Script executed:

# Let's check if this mirrors ESLint's jsx-a11y rule by searching online documentation
# First, check the original source attribution in comments or changelog
git log --all --format="%B" -n 20 | grep -i "noninteractive\|jsx-a11y\|eslint" | head -20

Repository: biomejs/biome

Length of output: 122


🏁 Script executed:

# Check if there's any Svelte-specific event handling mentioned
rg "svelte\|Svelte" crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs -B 5 -A 5

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Look at the Svelte test directory to see if ondoubleclick is tested there
cat crates/biome_html_analyze/tests/specs/a11y/noNoninteractiveElementInteractions/svelte/*.html 2>/dev/null

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Let me check if there's any ESLint jsx-a11y documentation referenced
rg "jsx-a11y\|eslint" crates/biome_html_analyze/src/lint/a11y/ -l

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check the rule options to see if there's any configuration
cat crates/biome_rule_options/src/no_noninteractive_element_interactions.rs

Repository: biomejs/biome

Length of output: 427


🏁 Script executed:

# Let's verify what pointer events are in the standard
# and whether they should be included instead of touch events
rg "onpointer" crates/biome_html_analyze/src/lint/a11y/ -l

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if there are any other HTML event handlers we're missing
cat crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs | tail -20

Repository: biomejs/biome

Length of output: 558


Remove ondoubleclick — it's not a valid HTML event attribute.

The standard attribute is ondblclick (already present on line 131). ondoubleclick won't trigger any browser behaviour and will only cause confusion. If you're trying to catch developer typos, that logic belongs in a different linter rule, not in an accessibility rule that checks for actual event handlers.

Touch events (ontouchstart, ontouchend, etc.) are notably absent, though they're widely used. The modern standard uses pointer events (onpointerdown, onpointerup, etc.) instead, which are also missing. Worth considering whether this list is intentionally scoped to just mouse/keyboard, or if it needs updating for modern input handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`
around lines 129 - 155, The INTERACTIVE_HANDLERS constant contains an invalid
HTML event name "ondoubleclick" that should be removed; update the slice in
no_noninteractive_element_interactions.rs to delete the "ondoubleclick" entry
(leave "ondblclick" intact) and run tests, and optionally consider whether to
separately add pointer/touch events in a different change if you intend to
support modern input handlers rather than developer-typo checks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither in the JS rule, not sure why those are missing 🤔

@ematipico ematipico left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nit

Comment thread crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`:
- Around line 69-74: The rule metadata for NoNoninteractiveElementInteractions
is missing a sources mapping; add a sources entry that mirrors the upstream JS
variant so migration and codegen can map back to ESLint. Update the
NoNoninteractiveElementInteractions metadata to include sources:
vec![RuleSource::Eslint("no-noninteractive-element-interactions").same()] (using
RuleSource::Eslint and the same() helper) to match the ESLint rule name and
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4eff7d9a-d27e-4125-a633-16b0607306f6

📥 Commits

Reviewing files that changed from the base of the PR and between 030207d and 585fb00.

📒 Files selected for processing (1)
  • crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs

Comment on lines +69 to +74
pub NoNoninteractiveElementInteractions {
version: "next",
name: "noNoninteractiveElementInteractions",
language: "html",
recommended: false,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Carry over the upstream sources mapping.

This is a straight port, but the rule metadata has no sources entry. That leaves generated rule metadata and biome migrate eslint with nothing to map back to the upstream rule. Please mirror the source annotation used by the JS variant here.

Based on learnings, Use RuleSource::Eslint("rule-name").same() when porting an ESLint rule with matching behavior, and RuleSource metadata affects codegen and biome migrate eslint detection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@crates/biome_html_analyze/src/lint/a11y/no_noninteractive_element_interactions.rs`
around lines 69 - 74, The rule metadata for NoNoninteractiveElementInteractions
is missing a sources mapping; add a sources entry that mirrors the upstream JS
variant so migration and codegen can map back to ESLint. Update the
NoNoninteractiveElementInteractions metadata to include sources:
vec![RuleSource::Eslint("no-noninteractive-element-interactions").same()] (using
RuleSource::Eslint and the same() helper) to match the ESLint rule name and
behavior.

@Netail Netail merged commit fb42ac4 into biomejs:next Apr 19, 2026
30 of 31 checks passed
@Netail Netail deleted the feat/port-no-noninteractive-element-interactions branch April 19, 2026 13:26
@github-actions github-actions Bot mentioned this pull request Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter A-Parser Area: parser L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants