[iOS][New Architecture] VoiceOver never announces "collapsed" for aria-expanded={false} (regression from RCTView)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 84/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- ios, objective-c, react-native
- Ambito
- accessibility, mobile
Direzione di ricerca
Inizia da RCTViewComponentView.mm, dove accessibilityState.expanded viene convertito nel valore di VoiceOver, e confrontalo con la gestione dello stato expanded in React/Views/RCTView.m. Esegui lo Snack collegato con VoiceOver su iOS e verifica che gli stati expanded false vengano annunciati come "collapsed", mentre gli stati true e checked rimangano corretti.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- C++
- Stelle
- 127k
- Fork
- 25.3k
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di react/react-native
-
Needs: Author Feedback Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
react/react-native#58659 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Needs: Author Feedback Needs: Repro
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 92/100
react/react-native#58621 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Add TypeScript declaration for the performance globalForse già presa Una pull request collegata a questa issue è aperta o già unita. ApertaNeeds: Attention Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
react/react-native#58610 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Needs: Triage :mag:
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
react/react-native#58565 · 2 commenti · 2 reazioni ·
I maintainer di solito rispondono entro 1 giorno
-
[Android][Fabric] addViewAt hard-crashes on a placeholder ViewState synthesised by updateEventEmitterForse già presa @wneel l’ha presa 20 giorni fa. ApertaNeeds: Attention Needs: Repro
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
react/react-native#58526 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di react/react-native
Issue simili
-
Make Catch2 optional when `RDK_BUILD_CPP_TESTS=OFF`Forse già presa @pechersky l’ha presa oggi. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 2 giorni
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
dice-group/dice-hash#111 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
MerginMaps/mobile#4741 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
ros-perception/image_pipeline#1198 ·