diff --git a/.changeset/fix-hr-presentation-role.md b/.changeset/fix-hr-presentation-role.md
new file mode 100644
index 000000000000..78749ee9ba26
--- /dev/null
+++ b/.changeset/fix-hr-presentation-role.md
@@ -0,0 +1,5 @@
+---
+"@biomejs/biome": patch
+---
+
+Fixed [#9024](https://github.com/biomejs/biome/issues/9024). The `noInteractiveElementToNoninteractiveRole` rule no longer incorrectly flags `
` elements with `role="presentation"` or `role="none"`. The `separator` role (implicit role of `
`) is now treated as non-interactive, matching the WAI-ARIA spec where a non-focusable separator is a static structural element.
diff --git a/crates/biome_aria_metadata/src/lib.rs b/crates/biome_aria_metadata/src/lib.rs
index 8f90c609ee7f..69b123839e93 100644
--- a/crates/biome_aria_metadata/src/lib.rs
+++ b/crates/biome_aria_metadata/src/lib.rs
@@ -160,13 +160,19 @@ impl AriaRole {
.find_map(|value| value.parse().ok())
}
- /// Returns `true` if the given role inherits of `AriaAbstractRole::Widget` and is not `Self::Progressbar`.
+ /// Returns `true` if the given role inherits of `AriaAbstractRole::Widget` and is not `Self::Progressbar` or `Self::Separator`.
///
/// This corresponds to a role that defines a user interface widget (slider, tree control, ...)
pub fn is_interactive(self) -> bool {
// `progressbar` inherits of `widget`, but its value is always `readonly`.
// So we treat it as a non-interactive role.
+ //
+ // `separator` inherits of both `structure` and `widget`, but it is only interactive
+ // when it is focusable (e.g. has `tabindex` and `aria-valuenow`).
+ // A non-focusable `separator` (such as `
`) is a static structural element.
+ // See: https://www.w3.org/TR/wai-aria-1.2/#separator
self != Self::Progressbar
+ && self != Self::Separator
&& self
.inherited_abstract_roles()
.contains(&AriaAbstractRole::Widget)
diff --git a/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx b/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx
index 4fb8419839d3..34a10e8aaaed 100644
--- a/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx
+++ b/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx
@@ -209,6 +209,8 @@
;
;
;
+
;
+
;
;
;
;
diff --git a/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx.snap b/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx.snap
index e33025cb2833..c4ed76c73913 100644
--- a/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx.snap
+++ b/crates/biome_js_analyze/tests/specs/a11y/noInteractiveElementToNoninteractiveRole/valid.jsx.snap
@@ -215,6 +215,8 @@ expression: valid.jsx
;
;
;
+
;
+
;
;
;
;