Code examples
Use semantic HTML
- There are two containers in the HTML that have the same counter content. One of them is hidden from screen readers by use of
aria-hidden="true"
and the other visually hidden container’s content is dynamically updated after a slight pause. This is to ensure the screen reader does not interrupt the announcement of the key pressed with the announcement of the dynamic counter text update. - While the visible counter text container is hidden with
aria-hidden="true"
it is still programmatically associated with the textarea by use ofaria-describedby
. This will ensure the text will be announced when the textarea receives focus. - Delay the update for dynamic
role="status"
counter- Use
setTimeout
to allow the accessibility tree and screen reader time to update in a logical fashion e.g. 1500ms
- Use
- Do not reference the
role="status"
element with aria-describedby- This causes a bug in VoiceOver
const textarea = document.getElementById('message');
if(textarea) {
const chars = document.getElementById('currentChars');
const srOutputTarget = document.getElementById('sr-counter-target');
textarea.addEventListener("input", event => {
const target = event.currentTarget;
const maxLength = target.getAttribute("maxlength");
const currentLength = target.value.length;
// update the visible counter text
chars.innerHTML = maxLength - currentLength;
// update the visually hidden counter text
setTimeout(function() {
srOutputTarget.innerHTML = maxLength - currentLength;
},1000);
});
}
<label for="message">
Your message
</label>
<textarea
id="message"
maxlength="50"
aria-describedby="charcounter">
</textarea>
<!-- Do not reference the status element with aria-describedby
Doing so will not work in VoiceOver -->
<div id="charcounter" class="hint" aria-hidden="true">
<span id="currentChars">50</span> of 50 <span class="hidden">characters remaining</span>
</div>
<div class="hidden" id="sr-counter-output-wrapper" role="status">
<span id="sr-counter-target">50</span> of 50</span> characters remaining
</div>
50 of 50 characters remaining