An input can have a visible hint and still fail to expose that hint as a programmatic description. One cause is a stale aria-describedby ID: the attribute names an element that is no longer on the page. This can happen when a component changes its error state or a template duplicates a form.
The W3C forms tutorial shows aria-describedby connecting a field to additional instructions. Its value is a space-separated list of IDs in the same document. That gives us a narrow check: every named ID should resolve to an element. It does not tell us whether the text is helpful, whether the field has a proper label, or whether a screen reader announces the right thing.
function missingDescriptions(root = document) {
return [...root.querySelectorAll("[aria-describedby]")].flatMap((control) => {
const ids = (control.getAttribute("aria-describedby") || "")
.trim().split(/\s+/).filter(Boolean);
return ids.filter((id) => !control.ownerDocument.getElementById(id))
.map((id) => ({ control, missingId: id }));
});
}
console.table(missingDescriptions().map(({ control, missingId }) => ({
field: control.name || control.id || control.tagName.toLowerCase(),
missingId,
})));
Run this in the browser console on a page with a form. Enter an invalid value and run it again. Some forms add an error description only after validation, so the initial page and error state deserve separate checks. Repeat after fixing the value: the description should still make sense when the state changes.
Here is a simple, working relationship to compare against:
<label for="email">Email address</label>
<input id="email" name="email" type="email" aria-describedby="email-help">
<p id="email-help">We will send a receipt to this address.</p>
If a validation error appears, connect the field to a clear message and expose its invalid state. W3C user-notification guidance demonstrates field-specific messages; its aria-invalid technique describes the error state. The message must be available where the user needs it, not just rendered as red text elsewhere.
<label for="email">Email address</label>
<input id="email" name="email" type="email"
aria-invalid="true" aria-describedby="email-help email-error">
<p id="email-help">We will send a receipt to this address.</p>
<p id="email-error">Enter an email address in the name@example.com format.</p>
This console check catches missing references only. It does not detect duplicate IDs, inaccessible hidden content, poor wording, or whether a validation message is announced at the right time. Inspect the accessibility tree, navigate with a keyboard, and test with assistive technology for the actual user experience. If JavaScript updates the form, test each meaningful state rather than only its first render.
An automated scan can help collect initial findings, while manual state testing handles behavior the first render cannot show. ADAFix’s accessibility review workflow is one option for starting that broader review; this small script is a focused developer check to run alongside it.
Top comments (0)