Skip to content

feat(biome_html_analyze): implement useAnchorContent rule for HTML#8769

Merged
ematipico merged 11 commits intobiomejs:nextfrom
rahuld109:use-anchor-content-html-v2
Jan 15, 2026
Merged

feat(biome_html_analyze): implement useAnchorContent rule for HTML#8769
ematipico merged 11 commits intobiomejs:nextfrom
rahuld109:use-anchor-content-html-v2

Conversation

@rahuld109
Copy link
Contributor

@rahuld109 rahuld109 commented Jan 14, 2026

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 useAnchorContent accessibility rule for HTML, as part of #8155.

  • Enforces that anchor elements have accessible content for screen readers
  • Flags empty anchors, whitespace-only content, self-closing anchors without accessible names, and content hidden with aria-hidden
  • Accepts aria-label and title attributes as valid accessible names (matching eslint-jsx-a11y behavior)
  • Provides an unsafe fix to remove aria-hidden attribute when present on the anchor element

Test plan

  • Added test cases for invalid HTML anchors (empty, whitespace, aria-hidden, nested hidden content, empty aria-label/title)
  • Added test cases for valid HTML anchors (text content, aria-label, title, nested visible content)
  • Added framework-specific tests for Vue, Svelte, and Astro
  • Verified custom components (PascalCase) don't trigger the rule
  • All tests pass with cargo test -p biome_html_analyze use_anchor_content
  • Clippy passes with no warnings

@changeset-bot
Copy link

changeset-bot bot commented Jan 14, 2026

🦋 Changeset detected

Latest commit: 3e0b8f3

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 Jan 14, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 14, 2026

Walkthrough

Adds a new HTML accessibility lint rule UseAnchorContent that flags anchors without accessible content (empty, whitespace-only, or fully aria-hidden), considers anchors with an accessible name (aria-label or title) valid, records aria-hidden for a potential auto-fix that removes it, emits diagnostics with WCAG references and actionable notes, registers the rule in the A11y lint group, and adds valid/invalid tests for HTML, Astro, Svelte and Vue fixtures.

Possibly related PRs

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing the useAnchorContent accessibility rule for HTML linting.
Description check ✅ Passed The description clearly explains the rule's purpose, behaviour, and includes comprehensive test coverage information relevant to the changeset.

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (1)

233-263: Consider extracting duplicated aria-hidden check.

The aria-hidden detection pattern (lines 233-242 and 254-263) is repeated verbatim for HtmlElement and HtmlSelfClosingElement. A small helper function would reduce duplication and centralise the logic.

♻️ Proposed refactor
+/// Checks if the given attribute represents a truthy aria-hidden value.
+fn is_aria_hidden_truthy(attribute: &HtmlAttribute) -> bool {
+    attribute
+        .initializer()
+        .and_then(|init| init.value().ok())
+        .and_then(|value| value.string_value())
+        .is_none_or(|value| !value.eq_ignore_ascii_case("false"))
+}

Then replace both inline checks with:

let has_aria_hidden = element
    .find_attribute_by_name("aria-hidden")
    .is_some_and(is_aria_hidden_truthy);

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0296c3b and 3e0b8f3.

⛔ Files ignored due to path filters (4)
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/invalid.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (5)
  • crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/invalid.vue
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/invalid.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 the dbg!() 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 (20)
📓 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 : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features
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
📚 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 : 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 : 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: 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: 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 `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 : 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 : Rule names should use the `no` prefix when the rule's sole intention is to forbid 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 : 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
📚 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/src/lint/a11y/use_anchor_content.rs
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.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 : 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/**/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/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.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/astro/invalid.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.svelte
⏰ 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)
  • GitHub Check: Documentation
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Check Dependencies
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_html_analyze)
🔇 Additional comments (8)
crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs (6)

13-83: Rule declaration follows all conventions.

The rule uses version: "next", includes fix_kind: FixKind::Unsafe since action is implemented, has proper documentation with Invalid/Valid examples, and the first paragraph is on a single line. WCAG references are well integrated.


85-88: State struct is appropriately minimal.


96-147: Run function logic is well-structured.

The flow correctly handles: aria-hidden on anchor → accessible name check → self-closing detection → parse validation → recursive content check. The defensive skip on parse errors (lines 133-136) is a sensible approach to avoid false positives.


149-183: Diagnostic and action implementation follows best practices.

The diagnostic provides clear guidance with WCAG references. The action correctly only triggers when aria_hidden_attribute is present, using the Markup! macro for the description.


185-195: Aria-hidden detection logic is correct.

The is_none_or pattern correctly treats missing values and any non-"false" values as truthy, matching HTML semantics where aria-hidden without a value is truthy.


336-347: Text content check is correct.

The implementation properly trims whitespace and handles dynamic content (text expressions, embedded content) conservatively to avoid false positives.

crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/invalid.svelte (1)

1-20: Comprehensive invalid test cases.

Good coverage of edge cases: empty anchors, whitespace-only, aria-hidden variants, nested hidden content, images without meaningful alt, void elements, and hidden inputs. These align well with the rule implementation.

crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro (1)

1-24: Astro test spec mirrors Svelte coverage.

Consistent test cases across frameworks ensure the rule behaves uniformly. The Astro frontmatter is correctly included.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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-hidden are 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> with alt).

crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astro (1)

5-11: Consider adding additional invalid cases for parity with invalid.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-label and title attributes

Not 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 alt attribute 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

📥 Commits

Reviewing files that changed from the base of the PR and between c594a36 and 479b756.

⛔ Files ignored due to path filters (8)
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_vue.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astro.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.svelte.snap is excluded by !**/*.snap and included by **
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (11)
  • .changeset/add-use-anchor-content-html.md
  • crates/biome_html_analyze/src/lint/a11y.rs
  • crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_astro.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_vue.vue
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_svelte.svelte
  • crates/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 the dbg!() 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.rs
  • crates/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.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_vue.vue
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid_astro.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid_svelte.svelte
  • crates/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.astro
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/invalid.html
  • crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/valid.html
  • 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 : 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.rs
  • 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.rs
  • 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.rs
  • 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 : 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.rs
  • 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.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.rs
  • 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.rs
  • 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.rs
  • 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.rs
  • 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 : 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_content module 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::Unsafe is appropriate since the rule implements action(). Based on learnings, the version: "next" and use prefix 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 run function 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-hidden removal case. Good use of the Markup! 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/title attribute 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 RouterLink as 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 for aria-label/title, and the valueless aria-hidden attribute. 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. NavLink is 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-hidden attribute edge cases, including the important distinction between "true" on children vs "false" on the anchor itself.


24-34: LGTM!

Comprehensive coverage of aria-label and title as 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.

@rahuld109 rahuld109 mentioned this pull request Jan 14, 2026
32 tasks
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 15, 2026

Merging this PR will not alter performance

✅ 4 untouched benchmarks
⏩ 152 skipped benchmarks1


Comparing rahuld109:use-anchor-content-html-v2 (3e0b8f3) with next (6340ce6)

Open in CodSpeed

Footnotes

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

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

Blocking because there are some logical mistakes to address

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 both HtmlElement and HtmlSelfClosingElement to 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

📥 Commits

Reviewing files that changed from the base of the PR and between 7de32ba and 1d147d9.

📒 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 the dbg!() 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. The FixKind::Unsafe is appropriate since removing aria-hidden can 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-hidden is present on the anchor itself.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

ematipico and others added 6 commits January 15, 2026 19:32
- 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
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