facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.09k stars 24.19k forks source link

Accessibility in android- With talkback elements are not clickable while on a screen from stack navigator. #45482

Closed stutiv48 closed 1 month ago

stutiv48 commented 1 month ago

Description

I'm using React Native with the Android platform. I'm using the Stack Navigator to navigate between screens. I've noticed that when I use the TalkBack accessibility service, the elements on the screen are not clickable.

I'm having an issue with accessibility in a screen that I call in the RootNavigator. When I call the screen directly, accessibility works fine. However, if I call the screen in stack navigation, only the first element of the screen is accessible, and the other elements are unclickable. I've tested this Voiceover it is working fine with stack navigation, and the issue only occurs with Talkback.

Steps to reproduce

React Native Version

0.71.8

Affected Platforms

Runtime - Android

Output of npx react-native info

System:
    OS: macOS 14.5
    CPU: (8) arm64 Apple M1
    Memory: 93.27 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 16.20.2 - ~/.nvm/versions/node/v16.20.2/bin/node
    Yarn: 3.6.4 - /opt/homebrew/bin/yarn
    npm: 8.19.4 - ~/.nvm/versions/node/v16.20.2/bin/npm
    Watchman: 2024.05.06.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.15.2 - /Users/stutiverma/.gem/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 23.5, iOS 17.5, macOS 14.5, tvOS 17.5, visionOS 1.2, watchOS 10.5
    Android SDK: Not Found
  IDEs:
    Android Studio: 2023.2 AI-232.10300.40.2321.11567975
    Xcode: 15.4/15F31d - /usr/bin/xcodebuild
  Languages:
    Java: 18.0.2.1 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 18.2.0 => 18.2.0 
    react-native: 0.71.8 => 0.71.8 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Stacktrace or Logs

-

Reproducer

 const Stack = createStackNavigator<RootStackParamList>();

const RootNavigator = () => {
  const navigation = useNavigation<BottomTabNavigationType>();

  useEffect(
    () => {
      const handleIncomingDeepLink = ({ url }: { url: string }) => {
        try {
          getDeepLinkUrl(url);
        } catch (error) {
          console.error(
            'Error handling deep link:', error,
          );
        }
      };

      const setupDeepLinking = async () => {
        try {
          const initialUrl = await Linking.getInitialURL();
          if (initialUrl) {
            handleIncomingDeepLink({
              url: initialUrl,
            });
          }

          Linking.addEventListener(
            'url', handleIncomingDeepLink,
          );
        } catch (error) {
          console.error(
            'Error setting up deep linking:', error,
          );
        }
      };

      setupDeepLinking();
    }, [getDeepLinkUrl],
  );

      const appStateListener = AppState.addEventListener(
        APP_EVENTS.APP_STATE_CHANGE, validateAuthToken,
      );
      return () => {
        appStateListener?.remove();
      };
    }, [
      authorizeUsingRefreshToken,
      isAuthenticated,
      navigation,
      resetAuthenticationState,
      tokenExpiryDate,
    ],
  );

  const initialRouteName = useMemo(
    () => {
      if (isAuthenticated) {
        return ROUTE.TAB_NAVIGATOR_ROOT;
      }
      return ROUTE.LOGIN_AND_REGISTER;
    }, [isAuthenticated],
  );

  return (
    <>
      <Stack.Navigator
        initialRouteName={initialRouteName}
        screenOptions={{
          headerShown: false,
          animationEnabled: true,
        }}
      >
        <Stack.Screen
          name={ROUTE.LOGIN_AND_REGISTER}
          component={LoginAndRegisterScreen}
        />
        <Stack.Screen
          name={ROUTE.TAB_NAVIGATOR_ROOT}
          component={TabNavigator}
        />
      </Stack.Navigator>
    </>
  );
};

export { RootNavigator };

LoginAndRegiterScreen

const LoginAndRegisterScreen = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = () => {
    // Basic validation for demonstration
    if (email === '' || password === '') {
      Alert.alert(
        'Error', 'Please enter both email and password',
      );
    } else {
      Alert.alert(
        'Success', 'Logged in successfully',
      );
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.label} accessibilityLabel="Email">
        Email
      </Text>
      <TextInput
        accessible
        accessibilityLabel="Email input"
        accessibilityHint="Enter your email address"
        style={styles.input}
        keyboardType="email-address"
        onChangeText={setEmail}
        value={email}
      />
      <Text style={styles.label} accessibilityLabel="Password">
        Password
      </Text>
      <TextInput
        style={styles.input}
        accessibilityLabel="Password input"
        accessibilityHint="Enter your password"
        secureTextEntry
        onChangeText={setPassword}
        value={password}
      />
      <TouchableOpacity
        accessibilityRole="button"
        accessibilityLabel="Login button"
        accessibilityHint="Press to login"
        onPress={handleLogin}
        style={styles.button}
      >
        <Text style={styles.buttonText}>Login</Text>
      </TouchableOpacity>
    </View>
  );
};

export { LoginAndRegisterScreen };

In first video stack navigation is used to render the login screen while in second one it is directly called

Screenshots and Videos

https://github.com/user-attachments/assets/9381e23b-1418-469b-a777-588c6ae5ebd2

https://github.com/user-attachments/assets/b1e20303-3aac-41e9-ac29-3c294e27a15e

github-actions[bot] commented 1 month ago
:warning: Unsupported Version of React Native
:information_source: It looks like your issue or the example you provided uses an unsupported version of React Native.

Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please upgrade to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on StackOverflow to get further community support.
cortinico commented 1 month ago

@stutiv48 Repros are mandatory. Please provide a repro with project/video 👍

stutiv48 commented 1 month ago

@cortinico I have added the repro along with video. Here the current screen page is Login_AND_REGISTRATION which is called through stack navigation. Through which only the first element is accessible but on calling it directly the it is working fine

cortinico commented 1 month ago

@stutiv48 the repro should be:

If your bug is UI related: a Snack If your bug is build/update related: use our Reproducer Template. A reproducer needs to be in a GitHub repository under your username.

stutiv48 commented 1 month ago

Repro link : https://snack.expo.dev/0qbt9oRMwfMIYyRyszTEy

stutiv48 commented 1 month ago

UPDATE : This issue solved by upgrading the react native version in the project 👍