Skip to content

[iOS][Fabric] Modal leaves an empty sheet when dismissed while presenting another view controller #58326

Description

@mozzius

Description

On iOS with Fabric, setting a Modal's visible prop to false while the modal's native view controller is presenting another view controller does not dismiss the modal itself.

The presented view controller disappears and React Native emits onDismiss, but the modal's page sheet remains onscreen without its React content. The resulting empty sheet cannot be dismissed.

This occurs in a real app when an async action closes a composer while iOS's Undo Typing alert is visible. It also reproduces in a Debug build when the modal is presenting React Native's developer menu, suggesting the issue applies to any presented view controller rather than the specific alert.

Expected behavior: dismissing the React Native Modal should dismiss the modal and any view controllers it presents, revealing the screen underneath.

The likely cause is that Fabric's RCTModalHostViewComponentView calls dismissViewControllerAnimated:completion: on the modal view controller itself. When that controller is presenting an alert or menu, UIKit dismisses only the presented child and runs the completion. React Native consequently emits onDismiss and removes the React content even though the modal remains presented.

Originally observed in bluesky-social/social-app#11393.

Steps to reproduce

Using the minimal reproducer:

  1. Install dependencies and launch the Release build with yarn ios --mode Release.
  2. Tap Open modal.
  3. Type anything in the text input.
  4. Tap Close modal in 5 seconds.
  5. Immediately shake the device and leave the Undo Typing alert open. In Simulator, choose Device → Shake or press Control-Command-Z.
  6. Wait for the timeout to set the Modal's visible prop to false.
  7. Observe that the alert disappears and onDismiss fires, but an empty page sheet remains stuck onscreen.

A normal yarn ios Debug build also reproduces the issue; shake opens React Native's developer menu instead of Undo Typing, but the same stuck sheet remains after the timeout.

React Native Version

0.87.1

Affected Platforms

  • Runtime - iOS
  • Build - macOS

Areas

  • Fabric - The New Renderer

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

System:
  OS: macOS 26.5.2
  CPU: (14) arm64 Apple M4 Pro
  Memory: 107.94 MB / 48.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 24.19.0
  Yarn:
    version: 1.22.22
  npm:
    version: 11.17.0
  Watchman:
    version: 2026.07.27.00
Managers:
  CocoaPods:
    version: 1.17.0
SDKs:
  iOS SDK:
    Platforms:
      - iOS 26.5
IDEs:
  Xcode:
    version: 26.6/17F113
Languages:
  Java:
    version: 17.0.20.1
  Ruby:
    version: 2.7.6
npmPackages:
  "@react-native-community/cli":
    installed: 20.2.0
    wanted: 20.2.0
  react:
    installed: 19.2.3
    wanted: 19.2.3
  react-native:
    installed: 0.87.1
    wanted: 0.87.1
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

No crash or error is logged. The Modal's onDismiss callback fires even though the native page sheet remains presented.

MANDATORY Reproducer

https://github.com/mozzius/modal-alert-dismiss-repro

Screenshots and Videos

Screen.Recording.2026-09-04.at.14.25.33-compressed.mp4

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions