Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility question: restoring and preventing focus to trigger on overlay/sheet dismissal? #29

Open
JayPanoz opened this issue Nov 20, 2024 · 4 comments

Comments

@JayPanoz
Copy link
Contributor

So in order to improve accessibility, React Aria restores focus to overlay triggers by default, and unlike other component libraries, no prop seems to be provided to prevent this on ready-to-use components, it requires FocusScope – and eventually something custom depending on the behaviour you’re trying to implement.

This means focus will be restored to the action buttons when the overlay/modal/sheet is dismissed, in all manners:

  • Escape key
  • Close button’ onPress within the overlay (click, tap, Enter and Space)
  • underlay onPress (outside the overlay)
  • MenuItem’s onAction (like onPress but for Menu)

Now, this perhaps creates a subpar experience with immersive mode, as it will then take 2 presses (click/tap) to toggle the mode: first one to focusOut/blur the trigger, second one to toggle the mode.

What would be ideal in terms of accessibility and usability to mitigate this issue?

It’s especially important to get that right as we may have to switch to custom components and implement this behaviour.

@JayPanoz
Copy link
Contributor Author

JayPanoz commented Nov 20, 2024

Note that right now, as an experiment on develop, the following behaviour is implemented for testing purposes on settings:

  • focus is restored to the trigger button on keyboard events, even if it’s in immersive mode;
  • it isn’t restored if the close button is pressed by other means;
  • it isn’t restored, and immersive mode is enabled if the underlay is pressed (tap/click outside of the overlay).

@bluefirepatrick
Copy link
Member

bluefirepatrick commented Nov 20, 2024

I am not sure the behavior listed is worth moving away from a more vanilla react-aria-components approach. Especially as react-aria-componets are in such a state of constant change and improvement. At this point I would recommend using the components as-is (which are hard enough to figure out and keep up with). So the decision is kind of: should we use react-aria-components, for better or worse, to which I would vote: yes. And I would advocate for as 'traditional' an approach to their implementation as is possible. This may well include using their hooks but perhaps not using stately. It's a hard call but that is my two cents.

@JayPanoz
Copy link
Contributor Author

@bluefirepatrick Thanks for your input. That’s very helpful.

Yeah, on second thought I’m resetting what I currently have on develop to try something else. It is how modals are expected to behave, as explained in multiple articles (aria-modal on MDN, Accessible Modals, etc.) so let’s not degrade accessibility in that case.

Given the issue is primarily tied to keyboard and tap/click, I’ll be exploring focus and focus-visible today, and how to handle immersive mode with a previous active element that was part of the UI – since of course the iframe is the active element when the tap/click is propagated in listeners.

We’ll probably have to set styles for focus anyway, so that they have enough contrast in all reading modes, as explained in this article by Sara Soueidan.

@danielweck
Copy link
Member

Keyboard focus management in "normal" web frontends is hard enough, but to do this correctly (i.e. with predictable outcome for users, in all different interaction paths, which may involve the mouse too) with nested iframes is quite hard. Just as in this project, in Thorium we face a similar challenge because an Electron webview is essentially an out-of-process sandboxed iframe hosted in shadow DOM.

Thankfully nowadays we don't have to "roll our own" half-baked GUI lib full of missing edge cases. That's what we did in Thorium pre-v3, but actually in the early days the test Electron app GUI was implemented with Google's Material Components for the Web which was VERY alpha and introduced breaking changes at a rapid pace (looking back, I am glad we discarded this option and chose to keep-it-simple with in-house minimal UI components).

I am a big proponent of Adobe's react-aria-components (Spectrum foundation) but there is also Radix etc. (personally I am a big fan of RAC's dedication to detail, the quality of their documentation, their pragmatic design and empirical testing/validation of a11y patterns).

Right now in Thorium we still have user navigation / focus steal bugs, the asynchronous nature of which makes it hard to troubleshoot and reason about. When a user follows a TOC hyperlink we force-focus inside the iframe DOM on Elements that are not focussable by default, so that screen readers are redirected to the correct location (well, by "correct" I mean HTML element, which is not quite character-level precision but this meets the vast majority of navigation needs, with some acceptable accuracy loss / tradeoff when linking into annotations or search results)

RAC or Radix (etc.) own built-in focus management certainly interferes with Thorium's own iframe focus in/out heuristics, and frankly at that point this is not a solved problem yet in Thorium v3 ... working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Draft
Development

No branches or pull requests

3 participants