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

IOS talkback read order. #31410

Closed
tanguven-santander opened this issue Apr 22, 2021 · 4 comments
Closed

IOS talkback read order. #31410

tanguven-santander opened this issue Apr 22, 2021 · 4 comments
Labels
Accessibility Team - Evaluated Accessibility Needs: Triage 🔍 Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@tanguven-santander
Copy link

Description

This bug is about accessibility. When the screen reader reads the contents from top to bottom, the order gets mixed because of the overlay sibling container. I've provided the code and a media about the issue.

wrongOrder.mov

React Native version:

System:
    OS: macOS 10.15.7
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 9.48 GB / 32.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.22.1 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 6.14.12 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.10.1 - /Users/e1213568/.rbenv/shims/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.3, DriverKit 20.2, macOS 11.1, tvOS 14.3, watchOS 7.2
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.3, 30.0.3
      System Images: android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom_64, android-29 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom_64, android-30 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.1 AI-201.8743.12.41.7199119
    Xcode: 12.3/12C33 - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_282 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.1 => 17.0.1 
    react-native: 0.64.0 => 0.64.0 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  1. Create two container.
  2. Pull the second container under the first one.
  3. Start the talkback and swipe right.
  4. Talkback skip the second item in the first container and read the first item in the second container.

Expected Results

expected.mov

Snack, code example, screenshot, or link to a repository:

import React from 'react';
import type {Node} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';

const App: () => Node = () => {
  const isDarkMode = useColorScheme() === 'dark';
  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />

      <View style={styles.headerContainer}>
        <View style={styles.headerContent}>
          <View style={styles.headerItem} accessible>
            <Text accessible accessibilityLabel="First">
              1
            </Text>
          </View>
          <View style={styles.headerItem} accessible>
            <Text accessible accessibilityLabel="Second">
              2
            </Text>
          </View>
        </View>
      </View>

      <View style={styles.listContainer}>
        <ScrollView style={backgroundStyle}>
          <View style={{height: 100}} />
          {Array.from({length: 5}, (i, ii) => (
            <View style={styles.listItem}>
              <Text key={`item-${ii}`}>{ii + 3}</Text>
            </View>
          ))}
        </ScrollView>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  headerContainer: {
    position: 'relative',
    zIndex: 20,
    backgroundColor: 'white',
    height: 200,
    opacity: 0.7,
  },
  headerContent: {
    flex: 1,
  },
  headerItem: {
    height: 100,
    width: '100%',
    padding: 10,
    justifyContent: 'center',
    alignItems: 'flex-start',
    backgroundColor: 'white',
  },
  listContainer: {
    borderTopWidth: 1,
    borderColor: 'red',
    position: 'relative',
    top: -102,
    zIndex: 10,
    height: '100%',
  },
  listItem: {
    height: 80,
    backgroundColor: 'pink',
    borderColor: 'white',
    width: '100%',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;
@blavalla
Copy link
Contributor

So what you've found here is an interesting wrinkle in the way that native platforms handle focus order. Both iOS and Android follow similar rules here, so I suspect this issue impacts both iOS and Android equally, though they aren't 100% identical so it's possible that your example happens to work on Android.

Generally speaking though, both platforms try to make focus match the visual order, from top-left to bottom-right, but both also take into account the view hierarchy itself to some degree when making this determination. Taking the visuals alone into account you'd expect that the order would be 1,2,3,4,5,6,7, but looking at the hierarchy makes it clear that 1,3,4,5,6,7,2 is the "correct" order.

The reason for this is that the pink container element around elements 2 through 7, while not focusable itself comes directly after element #1 visually. It's top position is above element #2. So what the screen reader sees is element #1 first, then the pink container element.

When it sees this, it doesn't just skip the container it because it's not focusable on its own, it starts walking down the tree from this element looking at its descendants. Since some of them are focusable, they are considered next in line, and focused next. Once it makes it through all of these descendants it continues walking the tree where it left off, and finally finds element #2.

Neither iOS nor Android take the z-position into account during this calculation, but you could imagine that if the pink container had a higher z-index than the gray one, and was visually on top, that this order would make a bit more sense.

There isn't really any workaround for this without the ability to manually define focus order, which RN doesn't currently support. The only "fix" would be to not trigger this in the first place by not making the container element higher than element #2.

@ArturKalach
Copy link

You can force focus order by specific native api.
I created a lib for that: https://www.npmjs.com/package/react-native-a11y

Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jan 10, 2024
Copy link

This issue was closed because it has been stalled for 7 days with no activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Accessibility Team - Evaluated Accessibility Needs: Triage 🔍 Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

3 participants