Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-use-semantic-elements-base-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9245](https://github.com/biomejs/biome/issues/9245): the [`useSemanticElements`](https://biomejs.dev/linter/rules/use-semantic-elements/) rule no longer suggests `<output>` for `role="status"` and `role="alert"`. The `<output>` element is only a `relatedConcept` of these roles, not a direct semantic equivalent. These roles are now excluded from suggestions, aligning with the intended behavior of the upstream `prefer-tag-over-role` rule.
13 changes: 11 additions & 2 deletions crates/biome_js_analyze/src/lint/a11y/use_semantic_elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ declare_lint_rule! {
/// <>
/// <input type="checkbox">label</input>
/// <hr/>
/// <div role="status"></div>
/// </>;
/// ```
///
Expand Down Expand Up @@ -97,9 +98,17 @@ impl Rule for UseSemanticElements {
// For the following roles, the associated elements are impractical:
// - combobox: <select> is not possible to implement many valid comboboxes (see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/)
// - option: <option> in browsers have divergent/unexpected behavior, with Safari hiding elements by default.
// - listbox: <datalist> isnt always correct for all listbox uses
// - listbox: <datalist> isn't always correct for all listbox uses
// See https://www.w3.org/WAI/ARIA/apg/patterns/combobox/. In most examples, roles are explicit
if role_value == "combobox" || role_value == "listbox" || role_value == "option" {
// - status: <output> is only a relatedConcept, not a baseConcept of the status role.
// Using <output> for status is misleading (see #9245, eslint-plugin-jsx-a11y#920)
// - alert: <output> is only a relatedConcept, same issue as status
if role_value == "combobox"
|| role_value == "listbox"
|| role_value == "option"
|| role_value == "status"
|| role_value == "alert"
{
return None;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<div role="paragraph" ></div>
<div role="complementary" ></div>
<div role="blockquote" ></div>
<div role="status" ></div>
<div role="contentinfo" ></div>
<div role="region" ></div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ expression: invalid.jsx
<div role="paragraph" ></div>
<div role="complementary" ></div>
<div role="blockquote" ></div>
<div role="status" ></div>
<div role="contentinfo" ></div>
<div role="region" ></div>

Expand Down Expand Up @@ -597,7 +596,7 @@ invalid.jsx:37:10 lint/a11y/useSemanticElements ━━━━━━━━━━
> 37 │ <div role="complementary" ></div>
│ ^^^^^^^^^^^^^^^^^^^^
38 │ <div role="blockquote" ></div>
39 │ <div role="status" ></div>
39 │ <div role="contentinfo" ></div>

i For examples and more information, see WAI-ARIA Roles

Expand All @@ -614,8 +613,8 @@ invalid.jsx:38:10 lint/a11y/useSemanticElements ━━━━━━━━━━
37 │ <div role="complementary" ></div>
> 38 │ <div role="blockquote" ></div>
│ ^^^^^^^^^^^^^^^^^
39 │ <div role="status" ></div>
40 │ <div role="contentinfo" ></div>
39 │ <div role="contentinfo" ></div>
40 │ <div role="region" ></div>

i For examples and more information, see WAI-ARIA Roles

Expand All @@ -625,159 +624,141 @@ invalid.jsx:38:10 lint/a11y/useSemanticElements ━━━━━━━━━━
```
invalid.jsx:39:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<output>

37 │ <div role="complementary" ></div>
38 │ <div role="blockquote" ></div>
> 39 │ <div role="status" ></div>
│ ^^^^^^^^^^^^^
40 │ <div role="contentinfo" ></div>
41 │ <div role="region" ></div>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:40:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<footer>

37 │ <div role="complementary" ></div>
38 │ <div role="blockquote" ></div>
39 │ <div role="status" ></div>
> 40 │ <div role="contentinfo" ></div>
> 39 │ <div role="contentinfo" ></div>
│ ^^^^^^^^^^^^^^^^^^
41 │ <div role="region" ></div>
42
40 │ <div role="region" ></div>
41

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:41:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:40:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<section>

39 │ <div role="status" ></div>
40 │ <div role="contentinfo" ></div>
> 41 │ <div role="region" ></div>
38 │ <div role="blockquote" ></div>
39 │ <div role="contentinfo" ></div>
> 40 │ <div role="region" ></div>
│ ^^^^^^^^^^^^^
42
43 │ {/* Constrained elements: tag matches but required attributes are missing */}
41
42 │ {/* Constrained elements: tag matches but required attributes are missing */}

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:44:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:43:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<input type="checkbox">

43 │ {/* Constrained elements: tag matches but required attributes are missing */}
> 44 │ <input role="checkbox" ></input>
42 │ {/* Constrained elements: tag matches but required attributes are missing */}
> 43 │ <input role="checkbox" ></input>
│ ^^^^^^^^^^^^^^^
45 │ <input role="radio" ></input>
46 │ <input role="searchbox" ></input>
44 │ <input role="radio" ></input>
45 │ <input role="searchbox" ></input>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:45:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:44:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<input type="radio">

43 │ {/* Constrained elements: tag matches but required attributes are missing */}
44 │ <input role="checkbox" ></input>
> 45 │ <input role="radio" ></input>
42 │ {/* Constrained elements: tag matches but required attributes are missing */}
43 │ <input role="checkbox" ></input>
> 44 │ <input role="radio" ></input>
│ ^^^^^^^^^^^^
46 │ <input role="searchbox" ></input>
47 │ <input role="textbox" ></input>
45 │ <input role="searchbox" ></input>
46 │ <input role="textbox" ></input>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:46:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:45:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<input type="search">

44 │ <input role="checkbox" ></input>
45 │ <input role="radio" ></input>
> 46 │ <input role="searchbox" ></input>
43 │ <input role="checkbox" ></input>
44 │ <input role="radio" ></input>
> 45 │ <input role="searchbox" ></input>
│ ^^^^^^^^^^^^^^^^
47 │ <input role="textbox" ></input>
48 │ <th role="columnheader" ></th>
46 │ <input role="textbox" ></input>
47 │ <th role="columnheader" ></th>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:47:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:46:12 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<input type="text">
<textarea>

45 │ <input role="radio" ></input>
46 │ <input role="searchbox" ></input>
> 47 │ <input role="textbox" ></input>
44 │ <input role="radio" ></input>
45 │ <input role="searchbox" ></input>
> 46 │ <input role="textbox" ></input>
│ ^^^^^^^^^^^^^^
48 │ <th role="columnheader" ></th>
49 │ <th role="rowheader" ></th>
47 │ <th role="columnheader" ></th>
48 │ <th role="rowheader" ></th>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:48:9 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:47:9 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<th scope="col">

46 │ <input role="searchbox" ></input>
47 │ <input role="textbox" ></input>
> 48 │ <th role="columnheader" ></th>
45 │ <input role="searchbox" ></input>
46 │ <input role="textbox" ></input>
> 47 │ <th role="columnheader" ></th>
│ ^^^^^^^^^^^^^^^^^^^
49 │ <th role="rowheader" ></th>
50 │ </>
48 │ <th role="rowheader" ></th>
49 │ </>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid.jsx:49:9 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:48:9 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<th scope="row">

47 │ <input role="textbox" ></input>
48 │ <th role="columnheader" ></th>
> 49 │ <th role="rowheader" ></th>
46 │ <input role="textbox" ></input>
47 │ <th role="columnheader" ></th>
> 48 │ <th role="rowheader" ></th>
│ ^^^^^^^^^^^^^^^^
50 │ </>
51
49 │ </>
50

i For examples and more information, see WAI-ARIA Roles

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
<div role="paragraph" />
<div role="complementary" />
<div role="blockquote" />
<div role="status" />
<div role="contentinfo" />
<div role="region" />
</>
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ expression: invalid_self_closing.jsx
<div role="paragraph" />
<div role="complementary" />
<div role="blockquote" />
<div role="status" />
<div role="contentinfo" />
<div role="region" />
</>
Expand Down Expand Up @@ -589,7 +588,7 @@ invalid_self_closing.jsx:37:10 lint/a11y/useSemanticElements ━━━━━━
> 37 │ <div role="complementary" />
│ ^^^^^^^^^^^^^^^^^^^^
38 │ <div role="blockquote" />
39 │ <div role="status" />
39 │ <div role="contentinfo" />

i For examples and more information, see WAI-ARIA Roles

Expand All @@ -606,8 +605,8 @@ invalid_self_closing.jsx:38:10 lint/a11y/useSemanticElements ━━━━━━
37 │ <div role="complementary" />
> 38 │ <div role="blockquote" />
│ ^^^^^^^^^^^^^^^^^
39 │ <div role="status" />
40 │ <div role="contentinfo" />
39 │ <div role="contentinfo" />
40 │ <div role="region" />

i For examples and more information, see WAI-ARIA Roles

Expand All @@ -617,51 +616,33 @@ invalid_self_closing.jsx:38:10 lint/a11y/useSemanticElements ━━━━━━
```
invalid_self_closing.jsx:39:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<output>

37 │ <div role="complementary" />
38 │ <div role="blockquote" />
> 39 │ <div role="status" />
│ ^^^^^^^^^^^^^
40 │ <div role="contentinfo" />
41 │ <div role="region" />

i For examples and more information, see WAI-ARIA Roles


```

```
invalid_self_closing.jsx:40:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<footer>

37 │ <div role="complementary" />
38 │ <div role="blockquote" />
39 │ <div role="status" />
> 40 │ <div role="contentinfo" />
> 39 │ <div role="contentinfo" />
│ ^^^^^^^^^^^^^^^^^^
41 │ <div role="region" />
42 │ </>
40 │ <div role="region" />
41 │ </>

i For examples and more information, see WAI-ARIA Roles


```

```
invalid_self_closing.jsx:41:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid_self_closing.jsx:40:10 lint/a11y/useSemanticElements ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The elements with this role can be changed to the following elements:
<section>

39 │ <div role="status" />
40 │ <div role="contentinfo" />
> 41 │ <div role="region" />
38 │ <div role="blockquote" />
39 │ <div role="contentinfo" />
> 40 │ <div role="region" />
│ ^^^^^^^^^^^^^
42 │ </>
43
41 │ </>
42

i For examples and more information, see WAI-ARIA Roles

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ export const Component2 = () => (
</Card>
</>

/* status role should not generate diagnostics (see #9245) */
<>
<div role="status"></div>
</>

{/* Semantic elements with a matching role should not be flagged (issue #5212) */}
<>
<nav role="navigation"></nav>
Expand All @@ -62,4 +67,3 @@ export const Component2 = () => (
<th role="columnheader" scope="col"></th>
<th role="rowheader" scope="row"></th>
</>

Loading
Loading