Skip to content

fullScreenModal dismiss freezes app on iOS Fabric (RN 0.83 + screens 4.22) #3648

@alex-vance

Description

@alex-vance

Description

When dismissing a fullScreenModal screen via router.dismiss() (which sends a POP action triggering native dismissViewControllerAnimated:), the app freezes completely. The UI becomes unresponsive and can only be recovered by force closing.

This is 100% reproducible and affects all fullScreenModal screens regardless of content — confirmed on multiple screens with completely different components (one with heavy Reanimated usage, one with none).

Reproduction

Environment:

  • react-native: 0.83.1
  • react-native-screens: ~4.22.0
  • expo-router: ~55.0.0-preview.7 (Expo SDK 55)
  • iOS Simulator, New Architecture (Fabric) enabled
  • Platform: iOS only

Steps:

  1. Create a Stack navigator with a screen using presentation: 'fullScreenModal' and gestureEnabled: false
  2. Navigate to that screen
  3. Call router.dismiss() (or any navigation action that dismisses the modal)
  4. Result: App freezes — UI thread hangs indefinitely

Workaround: Switching from fullScreenModal to card, modal, or transparentModal eliminates the freeze entirely. Only fullScreenModal (which uses UIModalPresentationFullScreen natively) triggers the bug.

Minimal layout example

// _layout.tsx
<Stack>
  <Stack.Screen name="index" />
  <Stack.Screen
    name="my-modal"
    options={{
      presentation: 'fullScreenModal',
      gestureEnabled: false,
      headerShown: false,
    }}
  />
</Stack>
// my-modal.tsx
import { useRouter } from 'expo-router';
import { Button, View } from 'react-native';

export default function MyModal() {
  const router = useRouter();
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="Dismiss" onPress={() => router.dismiss()} />
    </View>
  );
}

Analysis

The freeze appears to be a race condition in the native UIModalPresentationFullScreen dismissal lifecycle on Fabric. When dismissViewControllerAnimated: completes, the Fabric shadow tree reconciliation and screen unmounting seem to conflict, causing the JS thread to hang.

Other presentation types (card, modal, transparentModal) use different native presentation paths (UIModalPresentationPageSheet, etc.) and do not trigger this issue.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Missing infoThe user didn't precise the problem enoughMissing reproThis issue need minimum repro scenario

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions