diff --git a/.changeset/fix-use-anchor-content-image.md b/.changeset/fix-use-anchor-content-image.md new file mode 100644 index 000000000000..970a40daa00c --- /dev/null +++ b/.changeset/fix-use-anchor-content-image.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#9210](https://github.com/biomejs/biome/issues/9210): [`useAnchorContent`](https://biomejs.dev/linter/rules/use-anchor-content/) no longer reports an accessibility error for Astro `Image` components inside links when they provide non-empty `alt` text. diff --git a/crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs b/crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs index 524a8f58a051..1f8d9cc3f27b 100644 --- a/crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs +++ b/crates/biome_html_analyze/src/lint/a11y/use_anchor_content.rs @@ -143,7 +143,8 @@ impl Rule for UseAnchorContent { } // Check if the anchor has accessible content - if has_accessible_content(&html_element.children()) { + let is_astro = source_type.is_astro(); + if has_accessible_content(&html_element.children(), is_astro) { return None; } @@ -190,14 +191,14 @@ impl Rule for UseAnchorContent { } /// Checks if `HtmlElementList` contains accessible content (non-empty text or visible elements). -fn has_accessible_content(html_child_list: &HtmlElementList) -> bool { +fn has_accessible_content(html_child_list: &HtmlElementList, is_astro: bool) -> bool { html_child_list.into_iter().any(|child| match &child { AnyHtmlElement::AnyHtmlContent(content) => is_accessible_text_content(content), AnyHtmlElement::HtmlElement(element) => { if html_element_has_truthy_aria_hidden(element) { false } else { - has_accessible_content(&element.children()) + has_accessible_content(&element.children(), is_astro) } } AnyHtmlElement::HtmlSelfClosingElement(element) => { @@ -212,7 +213,10 @@ fn has_accessible_content(html_child_list: &HtmlElementList) -> bool { let tag_text = element.name().ok().and_then(|n| n.token_text_trimmed()); match tag_text.as_ref().map(|t| t.as_ref()) { - Some(name) if name.eq_ignore_ascii_case("img") => { + Some(name) + if name.eq_ignore_ascii_case("img") + || (is_astro && name == "Image") => + { html_self_closing_element_has_non_empty_attribute(element, "alt") } Some(name) @@ -235,6 +239,8 @@ fn has_accessible_content(html_child_list: &HtmlElementList) -> bool { }); !is_hidden } + // Custom components (PascalCase) may render accessible content + Some(name) if name.starts_with(|c: char| c.is_uppercase()) => true, _ => false, } } diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro index ef06ca900117..4c4a9fa9ab8c 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro @@ -16,6 +16,12 @@ + + + + + +

diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro.snap b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro.snap index 3a5cf1873e3e..e48117c9cae9 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro.snap +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/invalid.astro.snap @@ -1,5 +1,6 @@ --- source: crates/biome_html_analyze/tests/spec_tests.rs +assertion_line: 83 expression: invalid.astro --- # Input @@ -22,6 +23,12 @@ expression: invalid.astro + + + + + +

@@ -181,7 +188,7 @@ invalid.astro:17:1 lint/a11y/useAnchorContent ━━━━━━━━━━━ > 17 │ │ ^^^^^^^^^^^^^^^^^^^^^ 18 │ - 19 │ + 19 │ i All links on a page should have content that is accessible to screen readers. @@ -199,11 +206,55 @@ invalid.astro:20:1 lint/a11y/useAnchorContent ━━━━━━━━━━━ × Provide screen reader accessible content when using a elements. - 19 │ - > 20 │
+ 19 │ + > 20 │ + │ ^^^^^^^^^^^^^^^^ + 21 │ + 22 │ + + i All links on a page should have content that is accessible to screen readers. + + i Accessible content refers to digital content that is designed and structured in a way that makes it easy for people with disabilities to access, understand, and interact with using assistive technologies. + + i Follow these links for more information, + WCAG 2.4.4 + WCAG 4.1.2 + + +``` + +``` +invalid.astro:23:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Provide screen reader accessible content when using a elements. + + 22 │ + > 23 │ + │ ^^^^^^^^^^^^^^^^^^^^^^^ + 24 │ + 25 │ + + i All links on a page should have content that is accessible to screen readers. + + i Accessible content refers to digital content that is designed and structured in a way that makes it easy for people with disabilities to access, understand, and interact with using assistive technologies. + + i Follow these links for more information, + WCAG 2.4.4 + WCAG 4.1.2 + + +``` + +``` +invalid.astro:26:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Provide screen reader accessible content when using a elements. + + 25 │ + > 26 │
│ ^^^^^^^^^^^^^ - 21 │
- 22 │ + 27 │
+ 28 │ i All links on a page should have content that is accessible to screen readers. @@ -217,16 +268,16 @@ invalid.astro:20:1 lint/a11y/useAnchorContent ━━━━━━━━━━━ ``` ``` -invalid.astro:21:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.astro:27:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × Provide screen reader accessible content when using a elements. - 19 │ - 20 │
- > 21 │
+ 25 │ + 26 │
+ > 27 │
│ ^^^^^^^^^^^^^ - 22 │ - 23 │ + 28 │ + 29 │ i All links on a page should have content that is accessible to screen readers. @@ -240,14 +291,14 @@ invalid.astro:21:1 lint/a11y/useAnchorContent ━━━━━━━━━━━ ``` ``` -invalid.astro:24:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.astro:30:1 lint/a11y/useAnchorContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × Provide screen reader accessible content when using a elements. - 23 │ - > 24 │ + 29 │ + > 30 │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 25 │ + 31 │ i All links on a page should have content that is accessible to screen readers. diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro index 3b35fb09bc71..4a805afa0664 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro @@ -15,6 +15,7 @@ content content description +description Home diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro.snap b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro.snap index f31816c90732..ca412d20f6a9 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro.snap +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/astro/valid.astro.snap @@ -1,5 +1,6 @@ --- source: crates/biome_html_analyze/tests/spec_tests.rs +assertion_line: 83 expression: valid.astro --- # Input @@ -21,6 +22,7 @@ expression: valid.astro content content description +description Home diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte index 001fb72ddd66..e8fb306d85f5 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte @@ -16,3 +16,7 @@ + + +description + diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte.snap b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte.snap index 883b33c5036e..679d7053efa0 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte.snap +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/svelte/valid.svelte.snap @@ -23,4 +23,8 @@ expression: valid.svelte + +description + + ``` diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue index 49d641203266..03630f7be33f 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue @@ -16,4 +16,8 @@ + + + description + diff --git a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue.snap b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue.snap index be8f531c5fe2..5f1378d9c59d 100644 --- a/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue.snap +++ b/crates/biome_html_analyze/tests/specs/a11y/useAnchorContent/vue/valid.vue.snap @@ -22,6 +22,10 @@ expression: valid.vue + + + description + ```