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 issues with Turbo navigation #774

Open
khiga8 opened this issue Oct 21, 2022 · 6 comments
Open

Accessibility issues with Turbo navigation #774

khiga8 opened this issue Oct 21, 2022 · 6 comments

Comments

@khiga8
Copy link

khiga8 commented Oct 21, 2022

Hi Turbo team,

Our team migrated to using turbo drive and turbo frame in our Rails app around 3 months ago. We have received reports and discovered that turbo navigation poses accessibility issues for our screen reader users. Some of these issues, we can alleviate on our end through better guidance and additional accessibility feedback updates. Other issues, we do not see any workarounds for. We wanted to share our investigation and the feedback we’ve gotten with you.

Findings

Expected behavior

With a standard, hard page navigation, there are default mechanisms built in that allow a browser to communicate to a screen reader user that page navigation has taken place. For instance, when page navigation happens, the page title will be announced by the screen reader.

In addition, some screen readers have settings that can be toggled to specify what happens when loading a new web page like “Speak webpage summary” or “Automatically speak the webpage”. When these settings are toggled, a screen reader user can expect certain announcements to be made on page load.

Turbo frame

When a turbo frame navigation happens, there is no feedback given to screen reader users to indicate anything has happened.

Turbo drive

  • When a turbo drive navigation happens, there is inconsistent feedback given to screen reader users to indicate anything has happened. We saw inconsistent results across different screen reader and browser combinations.
    • With VoiceOver/Safari, the new page title is announced somewhat frequently.
    • With NVDA/Chrome, the announcement is much more infrequent or non-existent. The most commonly used screen readers are NVDA and JAWS so announcements being made in VoiceOver is not enough. (Source: WebAim: Screen Reader / Browser combinations)
      The screen reader settings for behavior that should happen at page load like, “Speak webpage summary” or “Automatically speak the webpage” are not respected, even in scenarios where the page title is announced.

Workarounds and Caveats

  • We worked around the lack of page navigation announcements by populating the aria-live region with the page title. We use this approach for both turbo frame and turbo drive navigations. However there are still caveats to this.
    • We noted above that with turbo drive, page title announcements are inconsistently made. As a result, we end up with duplicate page title announcements at times. We are not sure if there’s anything within turbo drive that results in page title announcements, but it is inconsistent and need to ensure it happens.
    • Similarly, with turbo drive, the entire body gets swapped out. aria-live region needs to be on the page, then updated dynamically for it to work. In order to trigger the announcement of the page title when a turbo drive navigation happens, we had to rely on a hack to insert an aria-live region to the page on page load, then update the content 200ms delay to trigger the announcement. This is not ideal.
  • We are also working internally to provide better guidance for turbo-frame use to avoid accessibility issues.
  • It’s worth calling out that aria-live regions are not supported on braille displays so aria-live regions aren’t enough to convey that something has happened. With a regular page navigation, the browser can communicate the page title as needed to display on the braille display. This means that people who rely on braille readers will not benefit from the aria-live workaround
  • We’ve determined there is no way for us to guarantee that the screen reader settings like “Speak webpage summary” or “Automatically speak the webpage”. This is not something we can or would want to implement ourselves.

Other issues

Because the focus can get completely lost on a turbo frame or turbo drive navigation, focus management is necessary. . We have found that some of this comes down to us using turbo frame when we shouldn’t be, but others of these, we’ll need to carefully manage focus, We are still figuring out how focus management should be handled in various scenarios but wanted to call out that this is a problem.

Videos

We've recorded some videos in a sandbox environment to demonstrate these findings below:

VoiceOver.not.respecting.user.settings.mp4

This video demonstrates the issues of turbo drive with VoiceOver/Safari.

  • I am navigating in a sandbox environment that has been set up for testing.
  • I have the VoiceOver utility settings open showcasing that the "Speak page summary" setting is on in VoiceOver.
  • I first navigate to a link with turbo drive disabled. VoiceOver announces the page title of the new link and provides a summary of the navigated page.
  • I then navigate with turbo enabled. With turbo drive, VoiceOver does announce the page title of the new link, but does not provide a summary of the navigated page as expected.
NVDA.Chrome.not.announcing.title.or.respecting.announcement.setting.mp4

This video demonstrates the issues of turbo drive with NVDA/Chrome.

  • I am navigating in a sandbox environment that has been set up for testing.
  • I have my NVDA settings open showcasing that the Automatic say all on page load box is checked.
  • I first navigate to a link with turbo drive disabled. NVDA reads out the page title and speaks everything on the page.
  • I then navigate back and to the same link with turbo drive enabled. With turbo drive, NVDA does not announce the page title nor does it respect the setting to speak everything on the page.
NVDA.Chrome.navigating.frames.mp4

This video demonstrates the issues of turbo frame with NVDA/Chrome.

  • I am navigating in a sandbox environment that has been set up for testing.
  • There are demos set up for basic frames, promoted frames, and target _top frames.
  • I first navigate through these links with turbo drive disabled. NVDA reads out the page title when I activate the links, and also announces all the content on the page, according to the Automatic say all on page load setting.
  • I then navigate through the same frames with turbo enabled. With turbo frame, nothing is announced indicating page navigation has happened.

In summary

While websites built in Rails can come with some accessibility benefits baked in, and Turbo enables these systems to incorporate more app-like behaviors, the way that Turbo is handling some specific cases of navigation negate those accessibility benefits.

We wanted to pass along our findings so that these concerns can be addressed appropriately and more accessibility guidance can be provided to consumers of Turbo, especially since Turbo is reaching wider adoption in the Rails community.

@manuelpuyol
Copy link
Contributor

manuelpuyol commented Oct 21, 2022

Here's the sandbox code in case anyone wants to test it out main...manuelpuyol:a11y-showcase

@brunoprietog
Copy link
Collaborator

Maybe it's controversial what I'll say, but as a blind user, one of the things I like most about SPAs is that I don't have to hear notices that a page changed or hear the page summary every time it loads. I simply enter on a link and continue using the application normally as if nothing happened. I understand that this doesn't respect the screen reader settings when changing pages, but that's really what you're looking for, to have the feeling that the page doesn't reload.

However, the focus management issue can be a bit awkward. For example, the button to add a star to a GitHub repository. If you press it, the screen reader should indicate that now the button is not to add a star, but to remove it. But that doesn't happen, the screen reader simply mutes and you have to move with up and down arrows to identify that the same button now says something else. I know that's not a turbo frame, but it's an example that has similar behavior and produces the same effect. I'm used to it and it doesn't bother me, but I admit that it can be confusing.

Another thing that might be useful is that Firefox with NVDA always announces page changes. On GitHub, this translates to always hearing page announcement messages twice, unless navigating using turbo frames.

While this might be a problem, I think there are other much more important accessibility issues. In my opinion, I would not consider these types of errors to be serious accessibility issues.

Thinking of some proposal to handle focus, one could listen to a global or Turbo frame visit and focus on some important element, such as the main region or an important element of the Turbo frame. I think this is much more comfortable than receiving the focus at the top of the page, but this is more a matter of personal taste and it is very difficult to reach agreements.

Maybe there could be some meta tag that contains the id of an element that turbo should focus on the next visit. There could also be another meta tag containing the announcement for screen readers.

Another option could be to default to announcing the page title every time a change occurs on the page. I don't think it's such a big deal to have a message announced twice, considering that most users stop announcements that are no longer relevant with the control key.

For a temporary solution, the announcement message could be in a permanent div with aria-live. Instead of replacing the body element every time turbo makes a visit, one would have to listen for the turbo:before-visit event, and look for an element like div#app, changing the element that is replaced. This trick works since Turbo 7.2 and is also recommended when there are iframes from external services that do not survive the replacement of the body element. In this way, the delay of the announcement to screen readers could be removed.

In addition, it is currently possible to focus on a specific element with the autofocus attribute each time turbo performs a visit. While the specification says that autofocus works with button, input, select and textarea HTML elements, I have been able to verify that it works with any element that can be focused by the browser using Turbo.

I think it is unfair to say that an application that uses Turbo has serious accessibility problems. As a blind user I really appreciate using applications like Hey, Basecamp or GitHub itself, even when you started using Turbo and did not announce page changes, and while it may be a drawback, I think it is much more serious not to respect things like header levels, regions, modal dialogs, cmboboxes, menus, etc.

I don't think developers using Turbo are making applications inaccessible just because of that. In my opinion, the conclusion is more alarmist than it really is.

Probably this discussion goes beyond what is expected from accessible web browsing in a SPA. Gatsby, for example, forces the screen reader to read the entire contents of the newly loaded page in all cases. Next.js only reads the title of the new page, which it extracts from the page title or a level 1 header.

Summarizing, I think a good starting point would be for Turbo to announce by default the change of a page title when browsing, giving some option to set up a custom announcement and an element to focus during the next visit.

What do you think? It would be interesting to hear more experiences from screen reader users.

@manuelpuyol
Copy link
Contributor

hi @brunoprietog, thanks so much for your input!

It's nice to know that you had positive experiences using Turbo, and we are going to try some of your suggestions, like announcing during before-visit.

Summarizing, I think a good starting point would be for Turbo to announce by default the change of a page title when browsing, giving some option to set up a custom announcement and an element to focus during the next visit.

I think this is spot on. Even though some issues may not be that bad, each application that uses Turbo has to implement some form of announcement/focus management, and if Turbo provided the tools for it, it'd make the navigation more standard for users.

@brunoprietog
Copy link
Collaborator

Hi @manuelpuyol,

I discovered something else yesterday.

If you apply morphdom when replacing instead of using replaceWith, I notice a big improvement in focus management.

import morphdom from "morphdom"

addEventListener("turbo:before-render", ({ detail }) => {
  detail.render = morphdom
})

For example, if I am in a navigation bar that has links and the link representing the current page is marked with aria-current="page", when I press enter on one of the links that redirects to a new page, the focus is not lost and the screen reader immediately says "current page".

So, I thought the same could result for turbo frames, and there is a big improvement. The problem is that sometimes it fails but I can't detect the error, and I don't know if there is some Turbo error when evolving an incorrect turbo frame or morphdom is not able to process the new turbo frame.

What do you think about this? Would you be willing to investigate something like this?

@seanpdoyle
Copy link
Contributor

Thank you for this thorough report!

Summarizing, I think a good starting point would be for Turbo to announce by default the change of a page title when browsing

In the past, I've attempted to resolve this shortcoming by including a visually hidden element with aria-live="assertive" as part of the server-rendered response. That element's usually the first child of the <body>:

<html>
  <head>
    <title><%= content_for(:page_title) %></title>
    <!-- the rest of the head -->
  </head>
  <body>
    <span class="sr-only" aria-live="assertive"><%= content_for(:page_title) %></span>
    <!-- the rest of the body -->
  </body>
</html>

Is that a suitable polypill for built-in announcements? Would that be a good pattern to codify into Turbo or Turbo Rails?

@brunoprietog
Copy link
Collaborator

Yes, it would be appropriate in my opinion, hopefully in Turbo, and after turbo:before-render, so that no one can avoid it unintentionally by replacing the body with one that doesn't include the announcement.

We have to remove the element after a few milliseconds or seconds, so that the user does not read that announcement at the top or bottom of the page. This is something that almost nobody does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants