[iOS][Fabric] Modal content vanishes from the accessibility tree on repeated present/dismiss cycles (renders on screen, invisible to XCUITest/VoiceOver; dev builds)
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 52/100
- Tipo de issue
- Bug
- Clareza
- Razoavelmente clara
- Status de atividade
- Ativa
- Stack de tecnologia
- react-native
- Domínio
- accessibility, mobile
Direção de pesquisa
Comece com o rn-modal-a11y-repro vinculado: execute cycle.yaml em um build Debug iOS e compare a primeira e a segunda apresentação usando a hierarquia do Maestro. Em seguida, rastreie o ciclo de vida do modal do Fabric em torno de RCTFabricModalHostViewController e das notificações de acessibilidade relatadas; considera-se concluído quando ciclos repetidos de apresentação/dispensa mantêm o modal e os elementos da tela base na árvore de acessibilidade, incluindo o fluxo existente orientado por acessibilidade.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Description
On the new architecture (Fabric), after one successful present/dismiss cycle of a <Modal transparent animationType="slide">, the next presentation renders on screen but registers nothing in the accessibility tree — the AX tree contains only status-bar/system elements. Touch still works: tapping the modal's close button by coordinates dismisses it and fully restores the accessibility tree; presenting again after that heal is blind again.
Reproduced in a bare community-CLI template (no Expo, no navigation library, one Modal), on both 0.86.2 and 0.87.0, using an XCUITest-based driver (Maestro) as the accessibility ground truth:
- Fresh launch → presentation 1 fully accessible → presentation 2 blind. Deterministic across app relaunches (Debug builds).
maestro hierarchyin the blind state shows only the status bar (time, battery, cellular) and the app root — no modal subtree, no base-screen elements.- Dismissing by coordinate tap restores everything; the next presentation is blind again.
- Build-mode asymmetry: Debug reproduces on the 2nd presentation every time; Release stayed clean for 40 cycles on the same app/simulator.
The failure state lives in the app process, not the test driver:
- Each open/close cycle above runs in its own
maestro testinvocation (fresh driver process each time) and the poison persists across them. - In the production app where we first hit this (larger surface, several modal hosts), a fresh XCUITest runner still sees the blind tree, and killing/respawning
testmanagerdmid-blindness changes nothing. There the trigger index varied slightly (2nd–3rd presentation, including cross-modal-host sequences: sheet ✓ → menu ✗, and menu ✓ menu ✓ → sheet ✗), so the exact index looks timing-sensitive; the minimal app settles on "2nd presentation". - The unified log shows correctly paired
kAXUserTestingNotificationpayloads (RCTFabricModalHostViewControllerViewDidAppear ↔ ViewDidDisappear) for every presentation including the blind ones — the modal VC lifecycle looks healthy while AX registration is missing. - Waiting 45s in the blind state does not self-heal; only dismissal heals.
AccessibilityInfo.setAccessibilityFocuson the modal content inonShowdoes not prevent it.
Impact: for assistive-technology users on dev builds, a blind modal's close control is not an accessibility element, so there is no announced way out (we could not script VoiceOver on the simulator to confirm end-to-end; the tree evidence above is from XCUITest snapshots, which share the AX infrastructure). For teams running XCUITest/Maestro/Appium suites against dev builds, any test past the second modal presentation fails on missing elements. Since Release builds did not reproduce in our runs, production users are plausibly unaffected — but we have not found what dev-mode dependency gates the bug, so we can't say that with confidence.
Possibly related, but describing different symptoms: #50152 (invisible undismissed modal layer), #48611, #49717.
Steps to reproduce
- Clone https://github.com/hubyrod/rn-modal-a11y-repro (bare
cli inittemplate + oneApp.tsx: a button presenting a transparent slide-animation Modal with a close button; Maestro flows included). npm install && cd ios && pod install && cd ..npx react-native run-ios --mode Debug(iOS simulator).maestro test cycle.yaml— passes (open → close via accessibility taps).maestro test cycle.yamlagain — fails: the modal is visibly presented but "CLOSE" is not in the accessibility tree.maestro hierarchyshows only status-bar elements.maestro test close-by-point.yaml(coordinate tap) — the modal dismisses and the tree is restored.maestro test open-only.yaml— blind again.
React Native Version
0.86.2 (also reproduced identically on a fresh 0.87.0 template)
Affected Platforms
Runtime - iOS, Build - MacOS
Output of npx react-native info
System:
OS: macOS 26.6.2
CPU: (14) arm64 Apple M4 Pro
Memory: 3.53 GB / 48.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.14.0
path: /Users/hugo/.nvm/versions/node/v22.14.0/bin/node
Yarn:
version: 1.22.22
path: /opt/homebrew/bin/yarn
npm:
version: 11.3.0
path: /Users/hugo/.nvm/versions/node/v22.14.0/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.17.0
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.5
- iOS 26.5
- macOS 26.5
- tvOS 26.5
- visionOS 26.5
- watchOS 26.5
Android SDK: Not Found
IDEs:
Android Studio: 2025.2 AI-252.28238.7.2523.14688667
Xcode:
version: 26.6/17F113
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.20
path: /usr/bin/javac
Ruby:
version: 4.0.6
path: /opt/homebrew/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.1.0
wanted: 20.1.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.86.2
wanted: 0.86.2
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Simulator: iPhone 17, iOS 26.2 runtime. AX probe: Maestro 2.4.0 (XCUITest driver).
Stacktrace or Logs
No crash. Accessibility hierarchy in the blind state (modal visibly presented,
screenshot available) reduces to status-bar/system elements only:
"accessibilityText" : "02:13" — status bar time
"accessibilityText" : "100 % battery power" — status bar
"accessibilityText" : "Cellular" — status bar
"accessibilityText" : "ModalA11yRepro" — app root node (no children with content)
After a coordinate-tap dismissal, the same probe returns the full tree
(OPEN button, counter text). Unified log shows paired
kAXUserTestingNotification payloads from RCTFabricModalHostViewController
(ViewDidAppear/ViewDidDisappear) for blind presentations as well.
Reproducer
https://github.com/hubyrod/rn-modal-a11y-repro
Screenshots and Videos
Screenshot of the blind state (modal fully rendered, presentations: 2) alongside the status-bar-only hierarchy dump is available on request — the reproducer regenerates both in under a minute.
- Linguagem predominante
- C++
- Estrelas
- 127k
- Forks
- 25.3k
- Métricas de merge de PRs
- Nenhum PR com merge em 30d
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de react/react-native
-
Needs: Author Feedback Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
react/react-native#58659 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
-
Needs: Author Feedback Needs: Repro
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 92/100
react/react-native#58621 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Add TypeScript declaration for the performance globalTalvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. AbertaNeeds: Attention Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100
react/react-native#58610 · 4 comentários ·
Mantenedores costumam responder em até 1 dia
-
Needs: Triage :mag:
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
react/react-native#58565 · 2 comentários · 2 reações ·
Mantenedores costumam responder em até 1 dia
-
[Android][Fabric] addViewAt hard-crashes on a placeholder ViewState synthesised by updateEventEmitterTalvez já em andamento @wneel assumiu há 21 dias. AbertaNeeds: Attention Needs: Repro
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100
react/react-native#58526 · 2 comentários ·
Mantenedores costumam responder em até 1 dia
Todas as issues de react/react-native
Issues semelhantes
-
Make Catch2 optional when `RDK_BUILD_CPP_TESTS=OFF`Talvez já em andamento @pechersky assumiu hoje. Abertabug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 2 dias
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
dice-group/dice-hash#111 ·
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 64/100
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
google/libaddressinput#255 ·
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 88/100
MerginMaps/mobile#4741 ·
Mantenedores costumam responder em até 1 dia