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

bug: ios, voiceover does not move to correct location after page transition #23650

Closed
5 of 6 tasks
Waligustav opened this issue Jul 16, 2021 · 12 comments · May be fixed by YoutacRandS-VA/eth2-beaconchain-explorer-app#2
Closed
5 of 6 tasks
Labels
package: core @ionic/core package type: bug a confirmed bug report

Comments

@Waligustav
Copy link

Waligustav commented Jul 16, 2021

Prequisites

Ionic Framework Version

  • v4.x
  • v5.x
  • v6.x

Current Behavior

Hi!

I stumbled upon a bug while implementing some accessibility functionality in an application

When navigating from page A to page B with voice-over within my application, the following issue appears. Upon entry to page B, the voice over-gets stuck on page A. Voice-over does not detect the correct contents inside page B. It looks like the voice-over keeps focusing on the recently clicked element from the previous page (A).

I have recorded functionality behaviour in the video linked below.

VoiceOverBugRecording.mov

Expected Behavior

When redirecting from "test page1" (A) to "test page2" (B) voice-over should immediately detect the first contents within the pages body so that the voice-over starts reading from the top of the page.

Steps to Reproduce

Project initiation

  • Download the repo
  • Open your CLI and navigate to the project folder
  • Type "npm install" and "ionic serve"

(macOS)

  • Go to system preferences > accessibility > shortcut > make sure every box is checked
  • Open the browser window that contains the project server > right click > inspect > toggle device toolbar "iphone X"
  • Press CMD while quickly pressing the "touch id" button 3 times
  • Refresh the browser window that contains the project server

Voice-over navigation

  • CAPS-lock + shift + down-arrow to enter the current area
  • CAPS-lock + shift + up-arrow to exit the current area
  • CAPS-lock + shift + right-arrow to skip the current area
  • CAPS-lock + space to "click" on a clickable link/button/item

Code Reproduction URL

https://github.com/Waligustav/ionicbugtest

Ionic Info

[WARN] Error loading @capacitor/ios package.json: Error: Cannot find module
'@capacitor/ios/package'

   Require stack:
   -
   /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/lib/project/index.js
   -
   /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/lib/index.js
   - /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/index.js
   - /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/bin/ionic

[WARN] Error loading @capacitor/android package.json: Error: Cannot find module
'@capacitor/android/package'

   Require stack:
   -
   /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/lib/project/index.js
   -
   /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/lib/index.js
   - /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/index.js
   - /Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli/bin/ionic

Ionic:

Ionic CLI : 6.16.3 (/Users/walibjork/.nvm/versions/node/v14.7.0/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/vue 5.6.11

Capacitor:

Capacitor CLI : 3.1.1
@capacitor/android : not installed
@capacitor/core : 3.1.1
@capacitor/ios : not installed

Utility:

cordova-res : not installed globally
native-run : 1.4.0

System:

NodeJS : v14.7.0 (/Users/walibjork/.nvm/versions/node/v14.7.0/bin/node)
npm : 6.14.7
OS : macOS Catalina

Additional Information

I upgraded a copy of the project to the Ionic 6 beta and tested the same functionality without any positive results.

I also tried this on a physical Iphone and voice-over seems to behave similarly.
Let me know if you want me to post more information about testing this issue on a physical device and i will provide you with more information.

@ionitron-bot ionitron-bot bot added the triage label Jul 16, 2021
@liamdebeasi
Copy link
Contributor

liamdebeasi commented Jul 19, 2021

Thanks for the issue. What version of iOS are you testing this on? The behavior I am seeing in both mobile Safari and in a Capacitor application is that the VoiceOver "focus" automatically moves to the new page when the page transition ends.

It might be better to use a physical device as baseline for your tests as the mobile views in desktop browsers only simulate the experience.

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Jul 19, 2021
@ionitron-bot ionitron-bot bot added triage and removed triage needs: reply the issue needs a response from the user labels Jul 19, 2021
@Waligustav
Copy link
Author

Thanks for the issue. What version of iOS are you testing this on? The behavior I am seeing in both mobile Safari and in a Capacitor application is that the VoiceOver "focus" automatically moves to the new page when the page transition ends.

It might be better to use a physical device as baseline for your tests as the mobile views in desktop browsers only simulate the experience.

Hi Liam, thanks for the quick reply

I am now testing this on iOS 14.0.1 (physical Iphone 11 pro device)

I can see that the "focus" moves to the new page after the page transition ends, but focus does not seem to be on the "correct" place. Focus jumps to an element on page B aligned at the same height as the last clicked element on page A.
If, for example the navigation link from the first page (A) is at the bottom of the screen, focus will jump to an item aligned at the bottom of the next page (B), not on the top of the page (B) screen.

And while testing this on macOS (10.15.7) it does not "focus" on the new page at all, as you can see in the attached video."

@liamdebeasi
Copy link
Contributor

Thanks I can reproduce this. I am not sure how much control we have over the VoiceOver focus, but I can do some more digging to see what is possible.

@Waligustav
Copy link
Author

Perfect Liam, thank you for taking your time to look into this issue!

@liamdebeasi liamdebeasi changed the title bug: Accessibility - voice-over stuck on previous page bug: webkit, voiceover does not move to correct location after page transition Oct 8, 2021
@liamdebeasi liamdebeasi changed the title bug: webkit, voiceover does not move to correct location after page transition bug: ios, voiceover does not move to correct location after page transition Oct 8, 2021
@liamdebeasi liamdebeasi added package: core @ionic/core package type: bug a confirmed bug report labels Oct 8, 2021
@ionitron-bot ionitron-bot bot removed triage labels Oct 8, 2021
@patrickhlauke
Copy link

Thanks I can reproduce this. I am not sure how much control we have over the VoiceOver focus, but I can do some more digging to see what is possible.

you move focus() programmatically and VO's focus will follow that. just make sure you either focus a focusable element (button, link, etc), or - if needing to move it to something traditionally not focusable - add tabindex="-1" to that element to signal that it's programmatically focusable at least.

Focus jumps to an element on page B aligned at the same height as the last clicked element on page A.

this is VoiceOver's error correction/fallback when the thing that last had focus is yanked from under its feet. it hunts for whatever element is in roughly the same place as the last-known-good focus location.

@liamdebeasi
Copy link
Contributor

liamdebeasi commented Sep 8, 2022

you move focus() programmatically and VO's focus will follow that. just make sure you either focus a focusable element (button, link, etc), or - if needing to move it to something traditionally not focusable - add tabindex="-1" to that element to signal that it's programmatically focusable at least.

The main thing that concerns me about programmatically moving focus() is determining the correct element to focus. In the past having Ionic determine what to focus has caused issues with app-level custom focus behaviors/autofocus/etc. There's more research needed here, but one potential solution could be to let developers customize what element gets focused (though we would want to understand the tradeoffs of that first).

@patrickhlauke
Copy link

sadly, that's the sort of pain you need to deal with when dynamically routing / changing page content. something that other frameworks have to tackle as well (see for instance https://dev.to/thisdotmedia/make-it-accessible-navigation-in-angular-2gee, https://www.upyoura11y.com/handling-focus/, etc)

@trustthevote
Copy link

Thanks much to Wali, Liam, and Patrick. We are having this problem as well, and it is a fix-or-fail on accessibility.

Liam, the last point you raise is a good one; I and my team would be happy to provide input.

In the meantime, Liam, can you point to a documented worked example that shows each page load doing an explicit set of the focus? In our case it would be nearly uniform (nearly every page starts with a header/title of the same style), but I would sure like to point my team to an Ionic example rather than having them experiment to re-discover the technique you describe -- even if it is just a hello-world

@liamdebeasi liamdebeasi mentioned this issue Jun 30, 2023
3 tasks
@liamdebeasi
Copy link
Contributor

In the meantime, Liam, can you point to a documented worked example that shows each page load doing an explicit set of the focus? In our case it would be nearly uniform (nearly every page starts with a header/title of the same style), but I would sure like to point my team to an Ionic example rather than having them experiment to re-discover the technique you describe -- even if it is just a hello-world

Hey there! Sorry, not sure how I missed this. I understand this reply may come too late, but one thing you can try is setting the focus of the page in the ionViewDidEnter lifecycle if you are using routing.

So something like this:

ionViewDidEnter() {
  titleEl.focus();
}

This ensures that the DOM nodes are in view, so you should be able to make the behavior consistent. However, there are a couple things to keep in mind:

  1. You will need to do this for every page in your app.
  2. Some platforms such as iOS have restrictions surrounding programmatically focusing elements that are not done as a result of user gestures, so there may be times when you cannot move focus manually (depending on when it happens).

I did some preliminary research on how to best solve this, and the way native apps (across both iOS and Android) do this is pretty inconsistent. Some will focus the title in the header, some in the content, and some focus something totally different. We are exploring ways we can make this behavior more predictable in Ionic, though we are intentionally being cautious as moving focus on behalf of the user can ruin an app's UX if not done correctly.

liamdebeasi added a commit that referenced this issue May 1, 2024
Issue number: resolves #23650

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

In traditional native applications, navigation will inform screen
readers that the view has changed. This allows screen readers to focus
the correct view. In a single page app on the web, this same concept
does not exist. As a result, transitioning from Page A to Page B results
in screen reader focus remaining on Page A. This means that users who
rely on screen readers are not informed of view changes.

Currently, developers are responsible for implementing this on their
own.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Introduces a new focus manager priority global config. When defined,
the app developer can specify which area of the view focus should be
moved to when the transition ends. The developer does this by specifying
areas in order of priority which allows for fallbacks in the event that
a particular UI component (such as a header) does not exist on a view.

There is some risk here by managing focus for the application. As a
result, this feature is considered experimental and disabled by default.
The team should collect feedback based on usage and enable it by default
when they feel this feature is stable enough.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

⚠️ Due to the `tsconfig.json` change, reviewers should restart the
Stencil dev server when checking out these changes locally.

Reviewers: Please test both of the test template files on physical iOS
and Android device with VoiceOver and TalkBack enabled, respectively.

Docs Link: ionic-team/ionic-docs#3627
@liamdebeasi
Copy link
Contributor

Thanks for the issue. This has been resolved via #29432, and this feature will be available in an upcoming release of Ionic Framework.

@Waligustav
Copy link
Author

Well done! 💪🏾

Copy link

ionitron-bot bot commented May 31, 2024

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators May 31, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
package: core @ionic/core package type: bug a confirmed bug report
Projects
None yet
4 participants