ionic-framework icon indicating copy to clipboard operation
ionic-framework copied to clipboard

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

Open Waligustav opened this issue 3 years ago • 8 comments

Prequisites

Ionic Framework Version

  • [ ] v4.x
  • [X] v5.x
  • [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.

https://user-images.githubusercontent.com/54717333/125956650-0ad6d929-7623-43a1-b4f0-54ad0d91b68e.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.

Waligustav avatar Jul 16 '21 14:07 Waligustav

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 avatar Jul 19 '21 16:07 liamdebeasi

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."

Waligustav avatar Jul 21 '21 08:07 Waligustav

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.

liamdebeasi avatar Jul 27 '21 15:07 liamdebeasi

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

Waligustav avatar Jul 27 '21 15:07 Waligustav

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.

patrickhlauke avatar Sep 08 '22 12:09 patrickhlauke

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).

liamdebeasi avatar Sep 08 '22 13:09 liamdebeasi

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)

patrickhlauke avatar Sep 08 '22 13:09 patrickhlauke

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

trustthevote avatar Sep 12 '22 17:09 trustthevote

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 avatar Jun 30 '23 13:06 liamdebeasi

Thanks for the issue. This has been resolved via https://github.com/ionic-team/ionic-framework/pull/29432, and this feature will be available in an upcoming release of Ionic Framework.

liamdebeasi avatar May 01 '24 14:05 liamdebeasi

Well done! 💪🏾

Waligustav avatar May 01 '24 21:05 Waligustav

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[bot] avatar May 31 '24 21:05 ionitron-bot[bot]