Skip to content

Android Talkback reads text styles #56873

Closed

Description

@uloco

Description

Reopening issue #55150 as it's still an existing problem in the latest react native version and the issue was closed without a proper fix.

Checkout my repro with a recent react native version.
It is just a <Text> component with no styles or anything

I also have provided a snack if you want to test it more easily with expo sdk 55
The snack is just the default snack template on sdk 55 stripped down to its basics with no dependencies.
https://snack.expo.dev/@uloco/expo-55-default-template

How to reproduce

  • Connect to your real android device and enable TalkBack.
  • Swipe right to select the first text element.
  • The screen reader says "Start 48 pixels color black, ..."

Expected behavior

The screen reader should only read the text and don't add any style properties.

Steps to reproduce

  1. Connect to your real android device and enable TalkBack.
  2. Swipe right to select the first text element.
  3. The screen reader says "Start 48 pixels color black, ..."

React Native Version

0.85.3

Affected Platforms

Runtime - Android

Output of npx @react-native-community/cli info

System:
  OS: macOS 26.4.1
  CPU: (8) arm64 Apple M1
  Memory: 181.42 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.17.1
    path: /Users/uloco/.local/state/fnm_multishells/36751_1779117177992/bin/node
  Yarn:
    version: 1.22.21
    path: /Users/uloco/.local/state/fnm_multishells/36751_1779117177992/bin/yarn
  npm:
    version: 9.6.7
    path: /Users/uloco/.local/state/fnm_multishells/36751_1779117177992/bin/npm
  Watchman:
    version: 2026.05.11.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods: Not Found
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 25.4
      - iOS 26.4
      - macOS 26.4
      - tvOS 26.4
      - visionOS 26.4
      - watchOS 26.4
  Android SDK: Not Found
IDEs:
  Android Studio: 2025.3 AI-253.31033.145.2533.15176040
  Xcode:
    version: 26.4.1/17E202
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.19
    path: /usr/bin/javac
  Ruby: Not Found
npmPackages:
  "@react-native-community/cli": Not Found
  react: Not Found
  react-native: Not Found
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: Not found
  newArchEnabled: Not found
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found

Stacktrace or Logs

no stacktrace or log

MANDATORY Reproducer

#56872

Screenshots and Videos

No response

Activity

  1. danyalahmed1995 commented on May 18, 2026

    @danyalahmed1995

    @uloco I opened #56881 to address this.

    I was able to trace the issue to the Android text accessibility delegate exposing the rendered Spanned text object through AccessibilityNodeInfoCompat.text. Since React Native attaches visual spans such as size/color spans during text construction, TalkBack can end up announcing those styling details instead of only the visible text.

    The PR keeps the rendered/source text unchanged, but normalizes the host accessibility node text to plain text when it is backed by a Spanned.

    I also added focused coverage for:

    • standard styled Text
    • prepared-layout text
    • preserving explicit contentDescription
    • preserving source clickable/style spans on the rendered text

    I verified the test fails with the production fix reverted and passes after restoring the fix. I could not manually validate TalkBack on a device/emulator in this session, so I called that out in the PR body.

  2. GBS05577-Andrea commented on May 19, 2026

    @GBS05577-Andrea

    @uloco may I ask you what physical device are you using?

    In one of my app I received a similar feedback lamenting layout and position were announced, but it happened on a OnePlus Nord 2T with Android 14 and I could not replicate the problem on an updated Google Pixel 8 Pro / 10 Pro, so I suspected it was due to the device or a custom implementation of screen reder announcements, since that device also presented additional strange behaviors when using the screen reader (like the green selection of the current element not exactly in place or quirks in the accessibility order).

    Unfortunatley I am still waiting for a retest and confirmation of my suspect, so it's just a (strong) hypothesis at the moment.

  3. uloco commented on May 19, 2026

    @uloco
    ContributorAuthor

    I am testing on a physical Google Pixel 9a on Android 16

  4. danyalahmed1995 commented on May 19, 2026

    @danyalahmed1995

    Okay so i did the test from my PR on a "physical" device

    Tested Device:

    • Device: OPPO CPH2219
    • Android: 13
    • RNTester debug build from this PR branch
    • TalkBack enabled
    • Metro running over USB with adb reverse tcp:8081 tcp:8081

    Manual validation:

    • Installed and launched RNTester on the device.
    • Navigated through RNTester with TalkBack focus enabled.
    • Verified TalkBack focus works across the Components, APIs, Playground, Image, and AccessibilityAndroid examples.
    • Verified styled/text-heavy RNTester examples remain focus able.
    • Verified clickable/link-style examples still expose focus able targets.
    • Verified the app continued running without crashing during the TalkBack navigation pass.

    This gives a device-level smoke test for the safety side of the change: the PR only normalizes the host accessibility node text, while rendered/source text remains available for visual rendering and clickable/link handling.

    Attached some screenshots and the log(sanitized) from the test sessions.

    Image Image Image

    rn-tester-talkback-sanitized-log.txt

  5. uloco commented on May 19, 2026

    @uloco
    ContributorAuthor

    @danyalahmed1995 please stop the slop. everybody knows you are AI and have no value to add. stop spamming the issue with your nonsense. i am waiting for replies from actual contributors / members of the repo.

  6. danyalahmed1995 commented on May 19, 2026

    @danyalahmed1995

    @uloco I attached the evidence report for what you are calling "slop" , if you need drama you are on the wrong platform meta also offers facebook you should try your luck there or if you are gonna use some swear words I suggest twitter (x) would be a good fit for it.

    Is that response ai slop too ?

  7. sanjaycpofficial-lab commented on May 21, 2026

    @sanjaycpofficial-lab

    🛠️ How to fix the "reads pixel styles" issue in React Native

    If TalkBack is aggressively reading raw style attributes (e.g., "62 pixels color black") on screen loads, re-renders, or when swiping past the last element, it's because Android is falling back to reading the raw TextView node instead of your accessibility labels.

    To completely fix this, you need a two-part approach: Wrap + Isolate and Explicit Focus Management.


    1. The "Wrap + Isolate" Pattern

    You must explicitly move your accessibility props to a wrapper <View>, and completely hide the inner <Text> from TalkBack using importantForAccessibility="no".

    ❌ The Problem (TalkBack reads styles):

    <Text accessibilityLabel="Step 1" style={{ fontSize: 24, color: 'black' }}>
      Step 1
    </Text>

    ✅ The Fix (TalkBack only reads the wrapper's label):

    <View 
      accessible={true} 
      accessibilityRole="text" // or "header"
      accessibilityLabel="Step 1"
    >
      {/* 👇 CRITICAL: This hides the raw style node from Android */}
      <Text importantForAccessibility="no" style={{ fontSize: 24, color: 'black' }}>
        Step 1
      </Text>
    </View>

    (💡 Tip: Apply this exact same pattern to text components inside your custom TouchableOpacity buttons).


    2. Explicit Focus Management (Fixes the Navigation / Looping Bug)

    Even with the fix above, when a screen mounts or a heavy re-render happens, TalkBack will sometimes drop focus to the OS window boundary, causing it to read layout sizes again.

    You must forcefully grab the focus when the screen opens using AccessibilityInfo.setAccessibilityFocus.

    import React, { useRef, useCallback } from 'react';
    import { View, Text, AccessibilityInfo, findNodeHandle } from 'react-native';
    import { useFocusEffect } from '@react-navigation/native'; // If using React Navigation
    
    export default function MyAccessibleScreen() {
      const headerRef = useRef<View>(null);
    
      // Force TalkBack to focus on the header when the screen loads
      useFocusEffect(
        useCallback(() => {
          const timer = setTimeout(() => {
            const reactTag = findNodeHandle(headerRef.current);
            if (reactTag) AccessibilityInfo.setAccessibilityFocus(reactTag);
          }, 300); // 300ms gives the UI time to settle
          
          return () => clearTimeout(timer);
        }, [])
      );
    
      return (
        // ⚠️ WARNING: Do NOT put importantForAccessibility="no-hide-descendants" 
        // on the root container, or TalkBack will skip the whole screen!
        <View style={styles.container}>
           
           <View 
             ref={headerRef}
             accessible={true}
             accessibilityRole="header"
             accessibilityLabel="My Screen Title"
           >
             <Text importantForAccessibility="no" style={styles.title}>
               My Screen Title
             </Text>
           </View>
    
           {/* Rest of your UI... */}
        </View>
      );
    }

    📋 Summary Checklist:

    • Never put accessible={true} or labels directly on stylized <Text> nodes.
    • Always wrap the text in a View, label the View, and put importantForAccessibility="no" on the <Text>.
    • Always manually trigger setAccessibilityFocus on mount to stop TalkBack from scanning the native root window boundary.
  8. neaucode commented on Jun 12, 2026

    @neaucode

    @danyalahmed1995 I agree with uloco that your comment has nothing to do with this issue and just detracts from it

    talkback is reading "Start 48 pixels color black, ..." but it should just be reading the text

    however, I'd guess this is an android talkback bug, nothing to do with react native

  9. danyalahmed1995 commented on Jun 12, 2026

    @danyalahmed1995

    @neaumusic okay you agree with them great , but this is not a 4chan voting poll if you want to talk about personal agreement and disagreement talk to them in inbox . The PR has proof that RN is leaking presentation/style spans into accessibility text and maintainer direction. If you can't be helpful kindly don't clout the issue with personal feelings. Kindly don't reply to this if it's not relevant to issue.

  10. neaucode commented on Jun 14, 2026

    @neaucode

    @neaumusic okay you agree with them great , but this is not a 4chan voting poll if you want to talk about personal agreement and disagreement talk to them in inbox . The PR has proof that RN is leaking presentation/style spans into accessibility text and maintainer direction. If you can't be helpful kindly don't clout the issue with personal feelings. Kindly don't reply to this if it's not relevant to issue.

    Lmao bro listen to yourself and get over the ego!! For what it's worth I don't care at all, just mentioned the original issue to get back on track.

    I believe Talkback 16.2 will read style for any text. What you just mentioned is relevant if you think the style is literally being written into the accessibility attributes, which I didn't realize and apologize for my misunderstanding

  11. uloco commented on Jun 15, 2026

    @uloco
    ContributorAuthor

    @neaumusic It's some ai bot, not a real person. No point in arguing, they will keep on. :D I think we should close this issue. The issue disappeared for me when I updated my android phone and talkback version.

  12. msachi commented on Oct 9, 2026

    @msachi

    'Fixed' it by applying this patch, which takes every text element and sets its accessibilityLabel to be its text. Works for me for simple elements, nested ones need to be fixed individually. Tested on 0.86.3.

    diff --git a/node_modules/react-native/Libraries/Text/Text.js b/node_modules/react-native/Libraries/Text/Text.js
    index 8e7b29c..5f706ad 100644
    --- a/node_modules/react-native/Libraries/Text/Text.js
    +++ b/node_modules/react-native/Libraries/Text/Text.js
    @@ -283,6 +283,31 @@ const TextImpl: component(
         return <NativeVirtualText {...processedProps} ref={forwardedRef} />;
       }
     
    +  if (Platform.OS === 'android' && _accessibilityLabel === undefined && children != null) {
    +    const childList = Array.isArray(children) ? children : [children];
    +    if (
    +      childList.every(
    +        child =>
    +          child == null ||
    +          typeof child === 'string' ||
    +          typeof child === 'number' ||
    +          typeof child === 'boolean',
    +      )
    +    ) {
    +      const plainText = childList
    +        .filter(child => typeof child === 'string' || typeof child === 'number')
    +        .join('');
    +      if (plainText.length > 0) {
    +        processedProps.accessibilityLabel = plainText;
    +      }
    +    }
    +  }
    +
       let nativeText = null;
     
       processedProps.accessible = _accessible;
    

    Of course it's a hack and it would be great to have a proper fix in the next react-native version.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions