The HTML aria-errormessage attribute
A field points at its error text with aria-errormessage, by id. The link counts only while the field's aria-invalid value flags an error, so the message has to be visible then, and hidden or unlinked the rest of the time.
Overview
The aria-errormessage attribute identifies the element that provides the error message for a field or widget, by its id. HTML has no attribute for this job, so there's nothing native to prefer. WAI-ARIA 1.2 deprecates global use, and the roles that keep it match those of aria-invalid.
The link depends on aria-invalid. Authors must use the two together. Setting aria-invalid to true makes the message pertinent, and browsers must not expose the link when aria-invalid is false. A valid field has aria-invalid=false or no aria-invalid at all.
The message has to keep pace with that state. While it's pertinent, it must not be hidden, so users can navigate to it. The rest of the time, authors must hide it or remove the attribute or its value. Browsers drop the link when the target is hidden or the id matches nothing.
A link doesn't draw attention to a message. You can use a live region, such as role="alert", when an error appears after an invalid value is entered. That tells assistive technology the user may benefit from the message even if it wouldn't otherwise be conveyed.
Syntax
<label for="start">Start time</label>
<input id="start" aria-invalid="true" aria-errormessage="start-err">
<p id="start-err">Use a time between 09:00 and 17:00.</p>
Values
| Value |
|---|
| A single element id. |
Example
<form id="slot">
<label for="start">Start time</label>
<input id="start" placeholder="10:30" aria-invalid="false">
<button>Book</button>
<p id="err" role="alert" style="color:#b91c1c;margin:8px 0"></p>
<p id="out" role="status" style="overflow-wrap:anywhere"></p>
<p>Enter 18:30 and press Book, then enter 10:30 and press it again.</p>
</form>
<script>
const form = document.getElementById('slot');
const start = document.getElementById('start');
const err = document.getElementById('err');
const out = document.getElementById('out');
form.addEventListener('submit', function (e) {
e.preventDefault();
const good = /^((09|1[0-6]):[0-5][0-9]|17:00)$/.test(start.value.trim());
start.setAttribute('aria-invalid', String(!good));
if (good) {
start.removeAttribute('aria-errormessage');
err.textContent = '';
out.textContent = 'Booked. aria-invalid is false, and the script removed aria-errormessage.';
} else {
start.setAttribute('aria-errormessage', 'err');
err.textContent = 'Invalid time. Use 24-hour time between 09:00 and 17:00.';
out.textContent = 'aria-invalid is true, and the script linked the message.';
}
});
</script>
Best practices
- Write an
aria-errormessagetarget that says what's wrong and what's required. For a time field, that means saying the time is invalid and giving the allowed range. - Update aria-invalid, the link and the message in one function, so a flagged field can't end up with an empty or stale message.
- Put an empty live region in the initial markup, then fill and link it when the value fails. Initial markup is the most reliable way to get a live region registered.
- As an alternative, let CSS reveal the message, hiding
.field-errorwithvisibility: hiddenand showing it through the selector[aria-invalid="true"] ~ .field-error.























