Allow a moz-button to be disabled but still receive keyboard focus
Categories
(Toolkit :: UI Widgets, enhancement)
Tracking
()
People
(Reporter: henry-x, Unassigned)
References
(Blocks 1 open bug)
Details
(Keywords: access)
In Tor Browser we have sometimes found it useful to allow a disabled button to still receive keyboard focus. I thought Firefox developers might also have an occasional use for this, so it might be useful to implement as part of moz-button so that this functionality can be used as XUL is replaced. If you don't think it will be used in Firefox then feel free to close this and I'll just modify moz-button downstream for Tor Browser instead.
To get an idea for why this might be useful, I'll give you an example of where we use this in Tor Browser. We have a 2-step dialog in our preferences. When the user presses the "Next" button, we need to perform some async operation before we can move to the next step, and during this operation the button should be functionally disabled. However, if we set the disabled attribute the user's focus will be kicked from the button, which is unnecessarily disorienting when using a keyboard, especially with a screen reader.
We have this pattern in a few places, where a button has some async operation, and needs to be functionally disabled during this time. And we want the presentation and ARIA semantics to reflect this.
To work around this, we don't set the disabled attribute and instead set
button.classList.add("spoof-button-disabled");
button.setAttribute("aria-disabled", "true");
with the styling
/* Make a button appear disabled, whilst still allowing it to keep keyboard
* focus. */
button.spoof-button-disabled {
/* Borrow the :disabled rule from common-shared.css */
opacity: 0.4;
/* Also ensure it does not get hover or active styling. */
pointer-events: none;
}
The "click" callback also has to be blocked or return early in javascript.
Comment 1•1 year ago
|
||
Sounds reasonable but I'd like to hear from the a11y team first
Comment 2•1 year ago
|
||
This seems reasonable, albeit a little unconventional. That said, while it makes sense for the button to keep focus when it is disabled (because otherwise focus would go to limbo or somewhere otherwise unexpected), I'm less certain about whether the button should be allowed to take focus when disabled if it wasn't already focused. Allowing the button to take focus in that case seems surprising, since the user can't do anything with it. Does this seem reasonable?
This would complicate the implementation somewhat, but I do think it's worth considering to avoid surprise.
| Reporter | ||
Comment 3•1 year ago
|
||
I'm less certain about whether the button should be allowed to take focus when disabled if it wasn't already focused. Allowing the button to take focus in that case seems surprising, since the user can't do anything with it. Does this seem reasonable?
I think that makes sense. In the Tor Browser case, the amount of time the button is "spoof disabled" is brief, so I didn't really consider the user tabbing away and back.
Implementation wise, I think you could get away with just setting tabIndex to -1, since pointer-events: none should also prevent it from being click-focusable.
| Reporter | ||
Comment 4•1 year ago
|
||
Given the above, would there ever be scenarios where you would want the user to loose button focus and for it to return to the top element? Otherwise we could just apply this universally for any disabled moz-button.
Comment 5•1 year ago
|
||
(In reply to Henry Wilkes (they/them) [:henry-x] from comment #3)
Implementation wise, I think you could get away with just setting
tabIndexto-1, sincepointer-events: noneshould also prevent it from being click-focusable.
It's worth noting that a screen reader or other accessibility client could still focus the button in this case, but that's probably okay. Focus won't make much of a difference there, since the control would have been "reachable" by the user regardless.
(In reply to Henry Wilkes (they/them) [:henry-x] from comment #4)
Given the above, would there ever be scenarios where you would want the user to loose button focus and for it to return to the top element? Otherwise we could just apply this universally for any disabled
moz-button.
I guess not. I can't think of any real examples. This isn't a change I'd want to make to HTML buttons at large, since that might break all sorts of things, but with moz-button, we have a lot more control with regard to where it's used, so I think it's reasonable unless we can come up with specific cases where it isn't.
| Reporter | ||
Comment 6•1 year ago
|
||
ok, thanks for the feedback :)
Comment 7•1 year ago
|
||
Henry, thinking about this some more I'm curious if it would make sense to move the focus within the dialog on the 2nd step? Is there some other interactive element or is it just a "please wait" loading page essentially? Perhaps there could be some label that you force focus on to read out that the loading label?
I'd like to avoid us adding support for this in moz-button if we don't have more concrete use cases that we'll definitely want it in
| Reporter | ||
Comment 8•1 year ago
|
||
(In reply to Mark Striemer [:mstriemer] from comment #7)
Henry, thinking about this some more I'm curious if it would make sense to move the focus within the dialog on the 2nd step? Is there some other interactive element or is it just a "please wait" loading page essentially? Perhaps there could be some label that you force focus on to read out that the loading label?
For the given example, we do show some text "loading" whilst the operation is being performed, which has role="alert". I had initially tried focusing the "loading" text, but it wasn't a great experience.
- The focus is force-moved twice in a short time. Which is potentially disorientating. In another scenario we have, the focus is meant to remain on the button, so the focus would switch away and back to the same location in a short amount of time.
- For visual keyboard users, the visible focus switching was also awkward.
- There isn't a good ARIA role for a bit of informative text that receives focus. E.g. the
alertandstatusroles are not meant to receive focus.
I did some digging in Firefox and I found two examples that would benefit from focus not being lost from a disabled button.
Save screenshot
- Switch on the "Always ask you where to save files" preference.
- Take a screenshot of the page with "Ctrl+Shift+S".
- Focus the "Download" button and hit "Enter".
- When the file chooser pops up cancel the operation (with "Escape").
When the focus returns, the "Download" button no longer has focus because it was temporarily disabled when the file chooser was opened.
Check for updates
- Navigate to the "Check for updates" button in "about:preferences".
- Press "Enter" and wait for it to complete.
The document.activeElement is now the page body, and the button has lost its focus styling. The user can return to the button with "Shift+Tab".
Description
•