feat(biome_html_analyze): implement useAnchorContent rule for HTML#8769
feat(biome_html_analyze): implement useAnchorContent rule for HTML#8769ematipico merged 11 commits intobiomejs:nextfrom
Conversation
🦋 Changeset detectedLatest commit: 3e0b8f3 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
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 |
WalkthroughAdds a new HTML accessibility lint rule Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (1)**/*.rs📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
🧠 Learnings (20)📓 Common learnings📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2025-12-22T09:26:56.943ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2025-12-31T15:35:41.261ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2025-09-25T12:32:59.003ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2026-01-02T14:58:16.536ZApplied to files:
📚 Learning: 2025-12-04T13:29:49.287ZApplied to files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
🔇 Additional comments (8)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs`:
- Around line 230-233: Remove the redundant is_non_empty_element check that
causes whitespace-only nested elements to pass; inside the branch that handles
non-hidden elements replace the OR expression using is_non_empty_element with a
sole call to has_accessible_content(&element.children()) so the recursive
accessibility check is authoritative (update the expression that currently reads
has_accessible_content(&element.children()) || is_non_empty_element(element) to
only call has_accessible_content).
🧹 Nitpick comments (3)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (1)
235-250: Self-closing elements unconditionally treated as accessible content.All self-closing elements without
aria-hiddenare considered accessible (line 249). This might cause false negatives for elements like<br>or<hr>that don't provide meaningful accessible content.Consider checking for specific elements that actually provide accessible content (e.g.,
<img>withalt).crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astro (1)
5-11: Consider adding additional invalid cases for parity withinvalid.html.The core invalid scenarios are covered, but the HTML test file includes a few extra cases that might be worth adding here for completeness:
- Self-closing anchor (
<a />)- Uppercase tag (
<A></A>)- Empty/whitespace
aria-labelandtitleattributesNot blocking, as the HTML tests already exercise these paths, but it would ensure consistent coverage across frameworks.
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html (1)
21-22: Minor comment clarity suggestion.The comment implies "self-closing" provides content, but it's actually the
altattribute that provides the accessible name. Consider rewording for accuracy.📝 Suggested comment improvement
-<!-- Image with alt text (self-closing provides content) --> +<!-- Image with alt text provides accessible content --> <a><img alt="description" /></a>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_vue.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astro.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.svelte.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vue.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (11)
.changeset/add-use-anchor-content-html.mdcrates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rscrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astrocrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.sveltecrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_vue.vuecrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astrocrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.sveltecrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vue
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use thedbg!()macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests
Files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
🧠 Learnings (15)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule
Applied to files:
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astrocrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vuecrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astrocrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.sveltecrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.svelte
📚 Learning: 2025-12-04T13:29:49.287Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.
Applied to files:
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astrocrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.htmlcrates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : New rules must be placed inside the `nursery` group before promotion to other groups
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `Markup!` macro for diagnostic messages and code action descriptions to ensure proper formatting
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : The first paragraph of rule documentation must be written in a single line to ensure proper rendering in the rules overview table
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).
Applied to files:
crates/biome_html_analyze/src/lint/a11y.rscrates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule documentation must include an `## Examples` section followed by `### Invalid` and `### Valid` subsections, with Invalid appearing first
Applied to files:
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Code blocks in rule documentation must specify a language identifier and be tagged with `expect_diagnostic` for invalid examples or remain untagged for valid examples
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/src/lint/a11y.rs (1)
crates/biome_html_syntax/src/element_ext.rs (3)
name(56-71)name(223-225)name(247-252)
🪛 LanguageTool
.changeset/add-use-anchor-content-html.md
[uncategorized] ~5-~5: Possible missing comma found.
Context: ...ortitle` attributes providing a non-empty accessible name are considered valid.
(AI_HYDRA_LEO_MISSING_COMMA)
🔇 Additional comments (16)
crates/biome_html_analyze/src/lint/a11y.rs (1)
14-21: LGTM!The new
use_anchor_contentmodule is correctly registered and integrated into the A11y lint group following the established pattern.crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (5)
1-9: LGTM!Imports are appropriate and well-organised for the rule implementation.
11-74: LGTM!The rule declaration is well-documented with proper examples, WCAG references, and correctly configured metadata. The
fix_kind: FixKind::Unsafeis appropriate since the rule implementsaction(). Based on learnings, theversion: "next"anduseprefix convention are correctly applied.
76-79: LGTM!Clean and minimal state struct that captures just what's needed for the fix action.
87-130: LGTM!The
runfunction logic is well-structured, covering all the documented cases: empty anchors, whitespace-only content, aria-hidden on the anchor, and nested hidden content. The early returns make the flow easy to follow.
132-165: LGTM!The diagnostic provides clear guidance with WCAG references, and the action correctly targets only the
aria-hiddenremoval case. Good use of theMarkup!macro..changeset/add-use-anchor-content-html.md (1)
1-5: LGTM!The changelog entry accurately describes the new rule's behaviour and provides a documentation link. The grammar is fine as-is.
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte (1)
1-7: LGTM!Good coverage of invalid anchor scenarios for Svelte. The test cases align well with the documented rule behaviour.
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_vue.vue (1)
1-9: LGTM!Comprehensive invalid anchor test cases for Vue, mirroring the Svelte coverage. Good consistency across framework tests.
crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astro (1)
1-22: LGTM!Solid coverage of valid anchor scenarios for Astro. The test cases appropriately cover custom components (which should be ignored), various accessible content patterns, and the
aria-label/titleattribute approaches. Well-structured and consistent with the other framework test files.crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vue (1)
1-19: LGTM!Good coverage for Vue. Nice touch including
RouterLinkas a Vue-specific custom component example. The test cases are comprehensive and properly structured within the Vue SFC<template>block.crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html (1)
1-37: LGTM!Excellent test coverage. The edge cases are well thought out—particularly the case-insensitive uppercase
<A>check, the distinction between empty and whitespace-only values foraria-label/title, and the valuelessaria-hiddenattribute. Comments make each scenario crystal clear.crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.svelte (1)
1-18: LGTM!Consistent with the other framework test files and covers all the expected valid scenarios.
NavLinkis a sensible choice for a Svelte-specific custom component example.crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html (3)
1-7: LGTM!Good foundational test cases covering simple text and nested content scenarios.
9-19: LGTM!Solid coverage of the
aria-hiddenattribute edge cases, including the important distinction between"true"on children vs"false"on the anchor itself.
24-34: LGTM!Comprehensive coverage of
aria-labelandtitleas valid accessible names, matching eslint-jsx-a11y behaviour as intended.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Merging this PR will not alter performance
Comparing Footnotes
|
ematipico
left a comment
There was a problem hiding this comment.
Blocking because there are some logical mistakes to address
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs`:
- Around line 252-267: The current AnyHtmlElement::HtmlSelfClosingElement branch
is too permissive; update the logic to treat self-closing tags as accessible
only when they provide a meaningful accessible name: first respect aria-hidden
(keep has_aria_hidden semantics and return false if true), then check tag and
attributes on element — for <img> require a non-empty alt, for elements support
aria-label or title with non-empty strings, and for void elements like <br>,
<hr>, <input type="hidden"> treat as not accessible unless they have an explicit
accessible name; use element.find_attribute_by_name(...) and its
initializer/value/string_value helpers to evaluate emptiness and case, returning
true only when a valid accessible name is present.
🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (1)
233-267: Consider extracting duplicated aria-hidden checking logic.The truthy aria-hidden check at lines 233-242 and 255-264 duplicates the logic in
get_truthy_aria_hidden. You could create a small helper trait or function that works with bothHtmlElementandHtmlSelfClosingElementto reduce this repetition.♻️ Suggested approach
// Helper that works with any type having find_attribute_by_name fn has_truthy_aria_hidden_attr(attribute: Option<HtmlAttribute>) -> bool { attribute.is_some_and(|attr| { attr.initializer() .and_then(|init| init.value().ok()) .and_then(|value| value.string_value()) .is_none_or(|value| !value.eq_ignore_ascii_case("false")) }) }Then call it as
has_truthy_aria_hidden_attr(element.find_attribute_by_name("aria-hidden"))in both branches.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use thedbg!()macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests
Files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `Markup!` macro for diagnostic messages and code action descriptions to ensure proper formatting
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : The first paragraph of rule documentation must be written in a single line to ensure proper rendering in the rules overview table
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `rule_category!()` macro to refer to the diagnostic category instead of dynamically parsing its string name
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2025-12-31T15:35:41.261Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:41.261Z
Learning: In crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs, the `issue_number` field in `declare_lint_rule!` macro is optional and the vast majority of nursery rules do not need it. Do not recommend adding `issue_number` unless there's a specific reason.
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
📚 Learning: 2025-09-25T12:32:59.003Z
Learnt from: arendjr
Repo: biomejs/biome PR: 7593
File: crates/biome_service/src/workspace/server.rs:1306-1306
Timestamp: 2025-09-25T12:32:59.003Z
Learning: In the biomejs/biome project, do not flag compilation errors during code review as they are handled by the existing test infrastructure and CI. Focus on other code quality aspects instead.
Applied to files:
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
🧬 Code graph analysis (1)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (4)
crates/biome_service/src/workspace.rs (1)
markup(1223-1225)packages/@biomejs/plugin-api/index.d.ts (1)
Severity(1-1)crates/biome_js_syntax/src/file_source.rs (1)
version(281-283)crates/biome_analyze/src/rule.rs (3)
sources(641-644)same(252-257)recommended(626-629)
🔇 Additional comments (5)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (5)
1-11: LGTM!Imports are appropriate for the rule implementation.
13-83: Well-documented rule declaration.Good use of
version: "next"for the new rule, proper source attribution with.same(), and clear examples. TheFixKind::Unsafeis appropriate since removingaria-hiddencan change the accessibility tree behaviour. Based on learnings, this follows the conventions correctly.
85-88: LGTM!Clean state struct enabling the fix to conditionally remove
aria-hidden.
96-147: LGTM!The logic flow is well-structured: early returns for edge cases, sensible handling of self-closing elements, and appropriate error recovery to avoid false positives. The case-sensitivity distinction between HTML files and component frameworks is correctly implemented.
149-182: LGTM!Diagnostic provides clear guidance with WCAG references. The action correctly uses the state to conditionally offer the fix only when
aria-hiddenis present on the anchor itself.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
- Check aria-hidden first, return false if hidden - Check for explicit aria-label or title attributes - For <img>: require non-empty alt attribute - For void elements (<br>, <hr>, <wbr>, etc): never accessible - For <input type="hidden">: not accessible - Other self-closing elements without accessible name: not accessible Add missing negative test cases for self-closing elements: - <img> without alt or with empty alt - Void elements like <br>, <hr>, <wbr> - <input type="hidden"> Updated test files: HTML, Vue, Svelte, Astro
This reverts commit d4338e2.
Note
AI Assistance Disclosure: The Rust implementation in this PR was developed with Claude Code. While I have experience with web accessibility and a11y standards, I am still learning Rust.
Summary
Implements the
useAnchorContentaccessibility rule for HTML, as part of #8155.aria-hiddenaria-labelandtitleattributes as valid accessible names (matching eslint-jsx-a11y behavior)aria-hiddenattribute when present on the anchor elementTest plan
cargo test -p biome_html_analyze use_anchor_content