I'm struggling to implement an accessible input with increment/decrement behaviors, using an <input type="text" role="spinbutton" />
element in HTML/JavaScript. But it seems like with VoiceOver there are custom (fake?) input events for incrementing/decrementing which change the input's value in unexpected ways.
How do I make sure a user navigating the page with assistive technology doesn't get bad guidance from VoiceOver while trying to interact with my widget?
For example, using super trimmed-down code like this:
function logIt(...args) {
document.getElementById('output').appendChild(
document.createTextNode(`${args.join(', ')}\n`)
);
}
document.getElementById("myInput").addEventListener('input', (e) => {
debugger;
logIt(e.type, e.data, String(e));
e.target.setAttribute('aria-valuenow', e.target.value);
}, false);
document.getElementById("myInput").addEventListener('keydown', (e) => {
logIt(e.type, e.data, String(e));
}, false);
<input
id="myInput"
type="text"
role="spinbutton"
autocomplete="off"
defaultValue="1"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="100"
/>
</div>
<pre id="output"></pre>
... VoiceOver will describe the input as a "stepper" and give instructions on how to increment/decrement using the keyboard. But using those keyboard commands results in some weird math, as seen in this screen cap:
You can also see (from the "logging" in the screen cap) that when the user types input, an InputEvent
is triggered with event.type
being input
- but when the VoiceOver keyboard command for increment/decrement is used, a base-type Event
is triggered with event.type
again set to input
.
And this doesn't seem to be unique to my implementations of role="spinbutton"
. The jQuery UI spinner doesn't behave well when incremented/decremented using VoiceOver keyboard commands:
I even tried some of the w3c's examples for role="spinbutton"
:
... and even though VoiceOver described each of those UI controls as a "stepper" and gave instructions on how to increment/decrement them using the keyboard, those instructions didn't seem to work. Other keyboard behaviors worked - but the ones VoiceOver suggests don't.
What can I do to make sure that role="spinbutton"
markup works correctly with VoiceOver's increment/decrement keyboard commands?
I don't believe role="spinbutton"
is compatible with VoiceOver as it seems that VoiceOver hijacks the keydown events when using the VoiceOver cursor. So when focusing on an element with role="spinbutton"
VoiceOver instructs the user to use "Control-Option DownArrow" or "Control-Option UpArrow" to decrement or increment the value. When those keys are pressed the event does not make it to any JavaScript keyDown event handler so we can't detect that those keys have been pressed and can't implement the actual incrementing or decrementing of the value. So I'm not sure there is any way to use role="spinbutton"
and make it work with VoiceOver. The user will be given instructions that don't work and will be confusing.
As a workaround for an application that I'm working on I've implemented the key handling behavior described in the WAI ARIA authoring practices for spinbutton but I have not added role="spinbutton"
or the other aria attributes listed. Instead, I've added aria-live="assertive"
so that when the value is changed either by keyboard or clicking the increment/decrement buttons the user hears the new value. Additionally, I've added some visually hidden text that instructs the user on how to increment/decrement the value with the keyboard and associated that with the input using aria-describedby
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With