0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-06 22:10:10 -05:00

Update a11y.ts (#9567)

* improve error message and allow for aria-label, aria-labelledby, img alt and svg title

* add checks for input

* Update packages/astro/src/runtime/client/dev-overlay/plugins/audit/a11y.ts

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>

* Update .changeset/orange-trainers-learn.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

---------

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Oliver Speir 2024-01-17 06:10:08 -07:00 committed by GitHub
parent 1539e04a8e
commit 3a4d5ec800
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 67 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
"astro": minor
---
Improves the a11y-missing-content rule and error message for audit feature of dev-overlay. This also fixes an error where this check was falsely reporting accessibility errors.

View file

@ -358,13 +358,72 @@ export const a11y: AuditRuleWithSelector[] = [
},
{
code: 'a11y-missing-content',
title: 'Missing content on element important for accessibility',
message: 'Headings and anchors must have content to be accessible.',
title: 'Missing content',
message:
'Headings and anchors must have an accessible name, which can come from: inner text, aria-label, aria-labelledby, an img with alt property, or an svg with a tag <title></title>.',
selector: a11y_required_content.join(','),
match(element: HTMLElement) {
// innerText is used to ignore hidden text
const innerText = element.innerText.trim();
if (innerText === '') return true;
if (innerText !== '') return false;
// Check for aria-label
const ariaLabel = element.getAttribute('aria-label')?.trim();
if (ariaLabel && ariaLabel !== '') return false;
// Check for valid aria-labelledby
const ariaLabelledby = element.getAttribute('aria-labelledby')?.trim();
if (ariaLabelledby) {
const ids = ariaLabelledby.split(' ');
for (const id of ids) {
const referencedElement = document.getElementById(id);
if (referencedElement && referencedElement.innerText.trim() !== '') return false;
}
}
// Check for <img> with valid alt attribute
const imgElements = element.querySelectorAll('img');
for (const img of imgElements) {
const altAttribute = img.getAttribute('alt');
if (altAttribute && altAttribute.trim() !== '') return false;
}
// Check for <svg> with valid title
const svgElements = element.querySelectorAll('svg');
for (const svg of svgElements) {
const titleText = svg.querySelector('title');
if (titleText && titleText.textContent && titleText.textContent.trim() !== '') return false;
}
const inputElements = element.querySelectorAll('input');
for (const input of inputElements) {
// Check for alt attribute if input type is image
if (input.type === 'image') {
const altAttribute = input.getAttribute('alt');
if (altAttribute && altAttribute.trim() !== '') return false;
}
// Check for aria-label
const inputAriaLabel = input.getAttribute('aria-label')?.trim();
if (inputAriaLabel && inputAriaLabel !== '') return false;
// Check for aria-labelledby
const inputAriaLabelledby = input.getAttribute('aria-labelledby')?.trim();
if (inputAriaLabelledby) {
const ids = inputAriaLabelledby.split(' ');
for (const id of ids) {
const referencedElement = document.getElementById(id);
if (referencedElement && referencedElement.innerText.trim() !== '') return false;
}
}
// Check for title
const title = input.getAttribute('title')?.trim();
if (title && title !== '') return false;
}
// If all checks fail, return true indicating missing content
return true;
},
},
{