Skip to content

Conversation

regnerus
Copy link

@regnerus regnerus commented Oct 22, 2025

Description

Right-to-left layouts on iPad expose a UIKit quirk: when a sheet-style modal is presented, UIKit wraps a presented modal inside a UITransitionView, and in RTL that container is mirrored, reporting a negative X origin. Because RNSScreenView reused that mirrored frame, the React view kept the negative origin and the sheet remained shifted.

This PR normalizes the modal’s frame inside RNSScreen::viewDidLayoutSubviews. Whenever the screen is presented natively, we align it with its transition container’s bounds, which keeps the sheet centered from the very first animation frame.

Fixes react-navigation/react-navigation#12800.

Changes

  • Recenter the modal screen view to its container’s bounds when presented natively.
  • Document why the adjustment is necessary (RTL mirroring of UITransitionView).

Screenshots / GIFs

Before

Simulator Screenshot - iPad Pro 13-inch (M4) - 2025-10-21 at 13 35 21

The modal animates in and remains shifted to the right.

After

Simulator Screenshot - iPad Pro 13-inch (M4) - 2025-10-22 at 11 42 51

The modal animates in centered, with no offset.

Test code and steps to reproduce

  1. Clone the reproduction from [iOS][RTL] Modal presentation sheet offset to the left on iPad react-navigation/react-navigation#12800.
  2. In package.json, update the dependency to use the fix branch:
"react-native-screens": "github:regnerus/react-native-screens#fix/rtl-modal-centering"

Alternatively, apply the provided patch (see below).

  1. Force RTL via I18nManager.forceRTL(true) and 18nManager.allowRTL(true).
  2. Run on an iPad simulator and open the modal.
  3. Expected: the modal animates in centered with no offset.

Patch

If you prefer using a patch instead of the branch, apply the following:

diff --git a/node_modules/react-native-screens/ios/RNSScreen.mm b/node_modules/react-native-screens/ios/RNSScreen.mm
index b62a2e2..60311bf 100644
--- a/node_modules/react-native-screens/ios/RNSScreen.mm
+++ b/node_modules/react-native-screens/ios/RNSScreen.mm
@@ -1587,6 +1587,20 @@ - (void)viewDidLayoutSubviews
     }
 #endif
   }
+
+  if (self.screenView.isPresentedAsNativeModal) {
+    UIView *superview = self.view.superview;
+    if (superview != nil) {
+      // UIKit presents modals inside a UITransitionView. In RTL that container is mirrored and
+      // ends up with a negative `frame.origin.x`. Mirroring is transparent to UIKit, but copying
+      // that frame to the React view would shift it off-screen. Align the screen with the
+      // container's bounds instead so it starts centered on the first animation frame.
+      CGRect targetFrame = superview.bounds;
+      if (!CGRectEqualToRect(self.view.frame, targetFrame)) {
+        self.view.frame = targetFrame;
+      }
+    }
+  }
 }
 
 - (BOOL)isModalWithHeader

react-native-screens+4.16.0.patch

Checklist

  • Included code example that can be used to test this change
  • Ensured that CI passes

Align modal screens to their transition container’s bounds when presented natively. UIKit mirrors the intermediate UITransitionView in RTL, which previously left our modal view centered using a negative origin so the sheet slid in offset and snapped back afterward. Normalizing the frame in viewDidLayoutSubviews keeps the sheet centered from the first animation frame.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS][RTL] Modal presentation sheet offset to the left on iPad

1 participant