Code examples
Adding hint/help text
<label for="best-nato-letter">
The best NATO letter is:
</label>
<div class="description" id="best-nato-letter-description">
Example: Alpha, Bravo, Charlie
</div>
<input type="text"
id="best-nato-letter"
aria-describedby="best-nato-letter-description">
Example: Alpha, Bravo, Charlie
Adding an error
Note: The alert must be structured as below to function properly in VoiceOver, with the alert text nested inside the role="alert"
element.
<label for="favorite-nato-letter">
What is your favorite NATO letter?
<span>Required</span>
</label>
<div class="description" id="favorite-nato-description">
Example: Alpha, Bravo, Charlie
</div>
<div role="alert"
id="favorite-nato-alert"
class="alert inert">
<!--- Do not reference this alert element
directly with aria-describedby -->
<div id="favorite-nato-error">
<!--- Use JS to inject the alert here -->
</div>
</div>
<input type="text"
id="favorite-nato-letter"
aria-describedby="favorite-nato-error favorite-nato-description"
required>
<button id="show-error">
Toggle error
</button>
Example: Alpha, Bravo, Charlie
When there is no hint or alert
Using aria-describedby
with a uniqueID that doesn’t exist on page yet will generate errors in automated syntax checking tools.
If it’s not possible to remove the attribute, there are ways to avoid the error flag.
Option 1: Leave aria-describedby=""
empty until the hint exists (preferred)
This is preferred because the DOM is cleaner.
<label for="favorite-pickle">
What is your favorite pickle?
</label>
<input type="text"
id="favorite-pickle"
aria-describedby="">
<!-- Leave aria-describedby attribute empty -->
Option 2: Leave the empty hint element in the DOM
This technique shouldn’t have any significant side effects, but does leave surplus elements in the DOM which is gross.
<label for="favorite-snack">
What is your favorite healthy snack?
</label>
<input type="text"
id="favorite-snack"
aria-describedby="description-favorite-snack">
<div class="description" id="description-favorite-snack">
<!-- Leave the description element empty -->
</div>
Developer notes
Browser + screenreader quirks
- Screenreaders do not implement alerts uniformly and must be tested
- Just because an alert pattern works in one screenreader doesn’t mean it will work in all three
- The element referenced by the
aria-describedby
attribute cannot use therole="alert"
attribute (see example above for workaround). - NVDA will read the alert twice if it appears while the input is in focus: once from the
role="alert"
being injected and from thearia-describedby
association. - NVDA needs a fraction of a second to catch up with changes in the DOM, use a
setTimeout
to delay displaying the alert