# Modal navigation properly overlays root navigation

- **Pattern:** `ab-001862` (`mobile-navigation-linking.navigation-ux.modal-overlay`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001862
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001862)

## Why it matters

Mixing modal screens into the regular stack corrupts back-button semantics: dismissing what feels like a modal pops the user out of the flow they were mid-task in, or the modal sticks around as a permanent screen in history. Users expect modals to float above the app and close independently; anything else reads as a bug and spikes task-abandonment rates on forms and confirmations. iOS Human Interface Guidelines explicitly treat this as a presentation contract.

## Severity rationale

Medium because modals still display but back-button semantics and presentation animation feel broken to users.

## Remediation

Layer modals in a dedicated `Group` above root navigation with `presentation: 'modal'` so they overlay cleanly. In `src/navigation/RootNavigator.tsx`:

```tsx
<RootStack.Navigator>
  <RootStack.Group>
    <RootStack.Screen name="Root" component={TabsNavigator} />
  </RootStack.Group>
  <RootStack.Group screenOptions={{ presentation: 'modal' }}>
    <RootStack.Screen name="EditProfile" component={EditProfileModal} />
  </RootStack.Group>
</RootStack.Navigator>
```

Closing the modal now pops only the modal layer and returns to the prior tab state.

## Detection

- **ID:** `modal-overlay`
- **Severity:** `medium`
- **What to look for:** Check whether your app uses modal stacks. Look for separate modal navigators defined at the root level alongside tab/stack navigators. Examine whether modals pop correctly and don't affect the underlying stack's navigation.
- **Pass criteria:** Count all modal screen definitions (screens with `presentation: 'modal'`). Modal stacks must be defined separately and overlay root navigation. Pressing back in a modal must close only the modal and return to the previous screen in the root stack. At least 1 modal Group or separate modal navigator must exist if modals are used.
- **Fail criteria:** Modals are mixed with regular screens, causing confusing back button behavior. Modal stack is not layered correctly. Modal opening corrupts the navigation state.
- **Skip (N/A) when:** The app does not use modal navigation (0 modal screen definitions found).
- **Detail on fail:** `"Modal screens are mixed with regular screens in the same stack — back button behavior is confusing"` or `"Closing a modal doesn't properly restore underlying screen state"`
- **Remediation:** Define modals in a separate navigator above your root navigators:

  ```tsx
  <NavigationContainer linking={linking}>
    <RootStack.Navigator screenOptions={{ presentation: 'modal' }}>
      <RootStack.Group>
        <RootStack.Screen name="Root" component={RootNavigator} />
      </RootStack.Group>
      <RootStack.Group screenOptions={{ presentation: 'modal' }}>
        <RootStack.Screen name="Modal" component={ModalScreen} />
      </RootStack.Group>
    </RootStack.Navigator>
  </NavigationContainer>
  ```

  This ensures modals overlay cleanly and back button behavior is correct.

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-001862
