[iOS][New Architecture] VoiceOver never announces "collapsed" for aria-expanded={false} (regression from RCTView)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 84/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- ios, objective-c, react-native
- Lĩnh vực
- accessibility, mobile
Hướng nghiên cứu
Bắt đầu trong RCTViewComponentView.mm, nơi accessibilityState.expanded được chuyển đổi thành giá trị VoiceOver, và so sánh với cách xử lý trạng thái expanded trong React/Views/RCTView.m. Chạy Snack được liên kết với VoiceOver trên iOS và xác minh rằng các trạng thái expanded false được thông báo là "collapsed", trong khi các trạng thái true và checked vẫn chính xác.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
On iOS with the New Architecture, an element with aria-expanded={false}, or accessibilityState={{ expanded: false }}, is announced by VoiceOver with no state. For example, an accordion header built as <Pressable role="button" aria-expanded={false}> is read as "Returns, button". Once expanded it is read as "expanded", which works. A VoiceOver user cannot tell a collapsed section from an ordinary button.
The cause is in RCTViewComponentView.mm, where the accessibility value is built from the accessibility state:
if (accessibilityState.expanded.value_or(false)) {
[valueComponents
addObject:RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded")];
}
There is no branch for expanded == false. The code directly above it handles both values of checked, adding "checked" and "unchecked".
This is a regression from the old architecture. React/Views/RCTView.m announces both states:
[valueComponents addObject:rolesAndStatesDescription[[val boolValue] ? @"expanded" : @"collapsed"]];
The localised "collapsed" string already exists there, with the description "a menu, dialog, accordian panel, or other widget which is collapsed".
I checked the source of 0.81.0, 0.86.3, 0.87.1 and main at commit a4085264df (29 September 2026). All four have the Fabric code above. Android is not affected: TalkBack announces "collapsed".
Suggested fix, in RCTViewComponentView.mm:
if (accessibilityState.expanded.has_value()) {
[valueComponents
addObject:accessibilityState.expanded.value()
? RCTLocalizedString("expanded", "a menu, dialog, accordian panel, or other widget which is expanded")
: RCTLocalizedString("collapsed", "a menu, dialog, accordian panel, or other widget which is collapsed")];
}
Until then, apps can work around it on iOS by supplying the word as the accessibility value. The name stays unchanged:
<Pressable
role="button"
aria-expanded={open}
accessibilityValue={Platform.OS === 'ios' && !open ? { text: 'collapsed' } : undefined}
>
VoiceOver output on the device:
role="checkbox",aria-checked={false}(control, same code path): "Email me offers, checkbox, unchecked". The false state is announced.role="button",aria-expanded={false}: "Returns, button". No state.role="button",aria-expanded={true}: "Returns, expanded, button". Works.accessibilityRole="button",accessibilityState={{ expanded: false }}: "Delivery, button". No state.- With the workaround above: "Warranty, collapsed, button".
Expected: "collapsed" is announced for expanded: false, as it was with the old architecture and as TalkBack does.
Steps to reproduce
- Open the Snack below on an iPhone with VoiceOver on. Snack runs the New Architecture.
- Swipe to "Email me offers". VoiceOver says "unchecked". This is the control.
- Swipe to "Returns". VoiceOver says "Returns, button", with no state.
- Double-tap "Returns". VoiceOver says "expanded".
- Swipe to "Delivery". VoiceOver says "Delivery, button", with no state.
- Swipe to "Warranty", which uses the workaround. VoiceOver says "Warranty, collapsed, button".
React Native Version
0.86.3
Affected Platforms
Runtime - iOS
Output of npx @react-native-community/cli info
System:
OS: Windows 11 10.0.26200
CPU: (14) x64 Intel(R) Core(TM) Ultra 7 155U
Memory: 17.80 GB / 31.52 GB
Binaries:
Node: 24.15.0
npm: 11.12.1
npmPackages:
react: 19.2.3
react-native: 0.86.3
Run in Expo Go on Expo SDK 57, which uses the New Architecture.
Device: iPhone Air, iOS 26.7.
Stacktrace or Logs
No crash or error. This is an accessibility output bug. The VoiceOver output for each element is under Description.
MANDATORY Reproducer
https://snack.expo.dev/@saleeem4rahman/voiceover-collapsed-state-missing
Snack runs Expo SDK 54 (React Native 0.81). The VoiceOver output above was recorded on 0.86.3 with the same props, and the 0.81 source has the same code.
Screenshots and Videos
None. The behaviour is audible, not visible.
- Ngôn ngữ chính
- C++
- Star
- 127k
- Fork
- 25.3k
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của react/react-native
-
[Android] Unrecognized fontFamily silently falls back to the system font (no log, unlike iOS)Đang mởNeeds: Triage :mag: Platform: Android Platform: iOS
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
react/react-native#58750 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Needs: Author Feedback Needs: Repro
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
react/react-native#58659 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Needs: Author Feedback Needs: Repro
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 92/100
react/react-native#58621 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Needs: Author Feedback Needs: Repro
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
react/react-native#58610 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Needs: Triage :mag:
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
react/react-native#58565 · 1 bình luận · 2 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của react/react-native
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
mpfaffenberger/privateer_reimagined#658 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Broken links in the docsĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
microsoft/onnxruntime#33018 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
AXERA-TECH/ax-llm#81 ·
-
enhancement
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 78/100
ros-industrial/ros2_canopen#448 ·
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày