How do you support incrementing a `role="spinbutton"` with Voiceover?

richardjpleguen profile image Richard JP Le Guen ・2 min read

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.createTextNode(`${args.join(', ')}\n`)

document.getElementById("myInput").addEventListener('input', (e) => {
  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);
    <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:

animated screen capture of attempts to increment with VoiceOver keyboard

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:

animated screen capture of jQuery UI spinner being incremented using VoiceOver and the value changing to some unexpected scientific notation

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?


Editor guide