Skip to content

feat(html): port useValidAriaValues a11y rule to HTML#9928

Merged
dyc3 merged 5 commits into
biomejs:nextfrom
aviraldua93:feat/html-use-valid-aria-values
Apr 11, 2026
Merged

feat(html): port useValidAriaValues a11y rule to HTML#9928
dyc3 merged 5 commits into
biomejs:nextfrom
aviraldua93:feat/html-use-valid-aria-values

Conversation

@aviraldua93

Copy link
Copy Markdown
Contributor

Summary

Ports the useValidAriaValues lint rule from JSX to HTML, as part of the umbrella issue #8155.

What the rule does

Validates that aria-* attribute values match the expected types defined by the WAI-ARIA specification:

  • Boolean: true / false (e.g., aria-hidden)
  • Tristate: true / false / mixed (e.g., aria-checked)
  • Integer: whole numbers only (e.g., aria-level)
  • Number: any numeric value (e.g., aria-valuemax)
  • Token: one of a specific set of values (e.g., aria-orientation: horizontal / vertical)
  • TokenList: one or more from a specific set
  • IdReference / IdReferenceList: HTML identifiers (e.g., aria-labelledby)
  • String: non-empty text

Behavior

  • In .html files, attribute names are matched case-insensitively (e.g., ARIA-HIDDEN="true" is valid)
  • In Vue/Svelte/Astro, dynamic bindings (:aria-checked="expr", v-bind:aria-checked="expr") are skipped — the value is a runtime expression that can't be statically validated
  • Diagnostics include value-type-specific guidance (lists valid values for Boolean/Token/Tristate types)

Test plan

  • valid.html / invalid.html: Boolean, Tristate, Token, Integer, Number, IdReferenceList, case-insensitive attribute names
  • vue/valid.vue / vue/invalid.vue: Vue framework coverage, dynamic binding skip verification

All 4 tests pass locally, clippy clean (zero warnings).

Closes part of #8155.

AI Disclosure

This PR was developed with assistance from GitHub Copilot CLI (Claude). The implementation and test cases were reviewed and verified by the author.

Ports the useValidAriaValues lint rule from JSX to HTML, as part of
the umbrella issue biomejs#8155.

The rule validates that aria-* attribute values match the expected
types defined by the WAI-ARIA specification:
- Boolean (true/false)
- Tristate (true/false/mixed)
- Integer, Number
- Token, TokenList (enumerated values)
- IdReference, IdReferenceList
- String

Case-insensitive attribute name matching in .html files.
Vue dynamic bindings (:aria-x, v-bind:aria-x) are skipped since
values are runtime expressions.

Includes HTML and Vue test fixtures (valid + invalid).

Closes part of biomejs#8155.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Apr 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9c0f9da

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 L-HTML Language: HTML and super languages labels Apr 11, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new HTML accessibility lint rule useValidAriaValues that validates static aria-* attribute values against WAI‑ARIA value types (Boolean, OptionalBoolean/Tristate, Token/TokenList, IdReferenceList, Numeric, Integer). The rule inspects plain HTML attributes (skips runtime Vue bindings), treats attribute names case‑insensitively for .html sources, treats valueless ARIA attributes as "true", and emits diagnostics with type‑specific guidance and a link to the WAI‑ARIA spec. A changeset and test fixtures (valid/invalid) were added for HTML, Vue, Astro and Svelte.

Suggested reviewers

  • dyc3
  • ematipico
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: porting the useValidAriaValues accessibility rule to HTML, which is the primary focus of this changeset.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing the rule's functionality, behaviour across file types, test coverage, and implementation notes.

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

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: 3

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

Inline comments:
In @.changeset/port-use-valid-aria-values-html.md:
- Line 5: Update the changeset text to link to the rule documentation and add a
tiny inline example: edit .changeset/port-use-valid-aria-values-html.md to
include a markdown link to the useValidAriaValues rule docs (e.g.,
"useValidAriaValues" -> [link]) and append a short HTML example showing an
invalid vs. corrected usage (e.g., an element with an invalid aria-* value and
the corrected value) so readers see the impact immediately.

In `@crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs`:
- Around line 108-150: Several diagnostic messages in the AriaValueType match
arms have grammar issues; update the user-facing strings in the match arms for
AriaValueType::Boolean, ::OptionalBoolean, ::Integer, ::Number, ::Tristate and
any similar literal messages used with diagnostic.footer_list or diagnostic.note
so they read correctly (e.g., "The only supported values for the
{attribute_name} property are one of the following:", "The only value supported
is a number without fractional components.", "The only supported value is a
number.", and "The only supported value for the {attribute_name} property is one
of the following:"); locate these messages in the AriaValueType match within
use_valid_aria_values.rs and replace the awkward phrasing ("is", "is number",
missing "is") with the corrected wording while keeping attribute_name
interpolation and existing helper calls (diagnostic.footer_list /
diagnostic.note) intact.
- Around line 84-95: The code currently short-circuits on valueless attributes
because html_attr.value()? returns None; update the logic in
use_valid_aria_values (where attribute_value, value_text and
aria_property.value_type() are used) to treat a missing value as the boolean
"true" (or otherwise normalize valueless aria-* to the equivalent string) before
checking aria_property.value_type().contains(&value_text), and add test fixtures
that include valueless aria attributes (e.g., invalid and valid HTML fixtures
exercising <div aria-hidden> and similar) to cover this case and document the
intended behavior; ensure UseValidAriaValuesState remains populated with
attribute_name and property_type as before.
🪄 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: b784b012-f52a-4103-ba49-ac9e568a823b

📥 Commits

Reviewing files that changed from the base of the PR and between 816302f and 6cd5e09.

⛔ Files ignored due to path filters (4)
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/vue/valid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (6)
  • .changeset/port-use-valid-aria-values-html.md
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/vue/invalid.vue
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/vue/valid.vue

"@biomejs/biome": minor
---

Ported the `useValidAriaValues` lint rule to HTML. This rule checks that all `aria-*` attribute values in HTML elements are valid according to the WAI-ARIA specification, including boolean, integer, token, and token list types.

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

Link the rule docs in the changeset (and add a tiny example).

Nice and concise, but for rule references this should link the rule documentation, and a brief inline example helps end users immediately see impact.

✍️ Proposed wording
-Ported the `useValidAriaValues` lint rule to HTML. This rule checks that all `aria-*` attribute values in HTML elements are valid according to the WAI-ARIA specification, including boolean, integer, token, and token list types.
+Ported [`useValidAriaValues`](https://biomejs.dev/linter/rules/use-valid-aria-values/) to HTML. Biome now validates static `aria-*` attribute values in HTML elements against WAI-ARIA types, catching invalid values such as `aria-hidden="yes"`.

As per coding guidelines: "for rule references, include links to the rule documentation" and "include examples with inline code snippets or code blocks for new rules".

📝 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
Ported the `useValidAriaValues` lint rule to HTML. This rule checks that all `aria-*` attribute values in HTML elements are valid according to the WAI-ARIA specification, including boolean, integer, token, and token list types.
Ported [`useValidAriaValues`](https://biomejs.dev/linter/rules/use-valid-aria-values/) to HTML. Biome now validates static `aria-*` attribute values in HTML elements against WAI-ARIA types, catching invalid values such as `aria-hidden="yes"`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/port-use-valid-aria-values-html.md at line 5, Update the
changeset text to link to the rule documentation and add a tiny inline example:
edit .changeset/port-use-valid-aria-values-html.md to include a markdown link to
the useValidAriaValues rule docs (e.g., "useValidAriaValues" -> [link]) and
append a short HTML example showing an invalid vs. corrected usage (e.g., an
element with an invalid aria-* value and the corrected value) so readers see the
impact immediately.

Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs Outdated
Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs
@codspeed-hq

codspeed-hq Bot commented Apr 11, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 67 untouched benchmarks
⏩ 161 skipped benchmarks1


Comparing aviraldua93:feat/html-use-valid-aria-values (9c0f9da) with next (816302f)

Open in CodSpeed

Footnotes

  1. 161 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.

- Handle valueless aria attributes (<div aria-hidden>) as 'true' per HTML spec
- Fix grammar in diagnostic messages ('values...is' -> 'values...are')
- Improve changeset with rule doc link and example
- Add valueless attribute test cases (valid + invalid)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@dyc3 dyc3 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.

Looks good.

Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs
Diagnostics now include pillar 3 (instruct user what to do):
'Use a valid value for the {attr} attribute according to the WAI-ARIA specification.'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aviraldua93

Copy link
Copy Markdown
Contributor Author

Thanks @dyc3 — good catch. Added the actionable guidance note to all diagnostic paths:

Use a valid value for the {attr} attribute according to the WAI-ARIA specification.

All 3 pillars now covered: what the error is, why it's wrong, and what to do about it.

@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 (1)
crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs (1)

72-77: Comment drift: implementation skips more than Vue directives.

Lines 72-73 read Vue-specific, but Lines 74-77 skip every non-HtmlAttribute variant. Worth tightening the comment so future readers do not assume Vue is special-cased here (apart from being one example).

🤖 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/use_valid_aria_values.rs` around
lines 72 - 77, The comment above the match that extracts html_attr is
misleadingly Vue-specific; update it to state that we only process plain HTML
attributes with static values and that all non-HtmlAttribute variants (e.g., Vue
directives and any other variants of AnyHtmlAttribute) are skipped. Mention the
relevant symbols AnyHtmlAttribute and html_attr (the match that returns None for
non-HtmlAttribute cases) so readers know this applies to every non-HtmlAttribute
branch, not just Vue.
🤖 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/use_valid_aria_values.rs`:
- Around line 80-83: The code currently lowercases every attribute name before
checking AriaAttribute::from_str, causing framework-specific props in
.vue/.svelte/.astro files to be misclassified; change the logic to inspect the
source file type and only perform case-folding for plain HTML files: keep the
original extracted name (from extract_html_attribute_name) for template files
(.vue, .svelte, .astro) and use name.to_ascii_lowercase_cow() only when the
current file is an .html file, then pass the appropriate string into
AriaAttribute::from_str so case-sensitive matching is preserved for template
files while .html remains case-insensitive.

---

Nitpick comments:
In `@crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs`:
- Around line 72-77: The comment above the match that extracts html_attr is
misleadingly Vue-specific; update it to state that we only process plain HTML
attributes with static values and that all non-HtmlAttribute variants (e.g., Vue
directives and any other variants of AnyHtmlAttribute) are skipped. Mention the
relevant symbols AnyHtmlAttribute and html_attr (the match that returns None for
non-HtmlAttribute cases) so readers know this applies to every non-HtmlAttribute
branch, not just Vue.
🪄 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: 32065de1-fb54-4147-b0e4-79564c8c6c39

📥 Commits

Reviewing files that changed from the base of the PR and between 279a468 and 314aef6.

⛔ Files ignored due to path filters (4)
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (1)
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs

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

@dyc3 dyc3 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.

Oof sorry i missed these on my first pass.

And I would appreciate it if you didn't have the AI write responses on your behalf.

Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs
Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs Outdated
Comment thread crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs Outdated
- State: String -> TokenText (zero-copy from CST)
- Value check: use &str reference instead of .to_string()
- Case-folding: only lowercase for .html files, preserve case in Vue/Svelte/Astro

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@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.

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

148-152: Minor wording inconsistency (optional).

For Token, the message uses singular "value ... is one of" while Boolean/Tristate use plural "values ... are". Both are grammatically correct, but harmonising would improve consistency.

🔧 Optional harmonisation
             AriaValueType::Token(tokens) => diagnostic.footer_list(
                 markup! {
-                    "The only supported value for the "<Emphasis>{attribute_name}</Emphasis>" property is one of the following:"
+                    "The only supported values for the "<Emphasis>{attribute_name}</Emphasis>" property are:"
                 },
                 tokens,
             ),
🤖 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/use_valid_aria_values.rs` around
lines 148 - 152, The footer message for AriaValueType::Token uses singular
phrasing ("The only supported value for the {attribute_name} property is one
of...") while Boolean/Tristate use plural; update the string in the
AriaValueType::Token diagnostic.footer_list invocation to plural phrasing to
match (e.g., "The only supported values for the {attribute_name} property are
one of the following:") so wording is consistent with Boolean and Tristate
messages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs`:
- Around line 148-152: The footer message for AriaValueType::Token uses singular
phrasing ("The only supported value for the {attribute_name} property is one
of...") while Boolean/Tristate use plural; update the string in the
AriaValueType::Token diagnostic.footer_list invocation to plural phrasing to
match (e.g., "The only supported values for the {attribute_name} property are
one of the following:") so wording is consistent with Boolean and Tristate
messages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b68ec02a-0f98-401b-aa52-0a3775ff6caf

📥 Commits

Reviewing files that changed from the base of the PR and between 314aef6 and 9c0f9da.

⛔ Files ignored due to path filters (1)
  • crates/biome_html_analyze/tests/specs/a11y/useValidAriaValues/invalid.html.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (1)
  • crates/biome_html_analyze/src/lint/a11y/use_valid_aria_values.rs

@dyc3 dyc3 merged commit aa82576 into biomejs:next Apr 11, 2026
17 checks passed
@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 L-HTML Language: HTML and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants