# Mobile Navigation Patterns

> Navigation patterns for mobile apps (stack, tab, modal, drawer, nested flows) with platform conventions across SwiftUI, Compose, Flutter, and React Native. Use when structuring navigation or handling deep links.

- Skill: `almasumdev/mobile-navigation-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add almasumdev/mobile-navigation-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/almasumdev/mobile-navigation-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: almasumdev (https://skillmd.com/u/almasumdev)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/almasumdev/mobile-navigation-patterns

---


# Mobile Navigation Patterns

## Instructions

Navigation is the skeleton of a mobile app. Choosing the wrong pattern creates lost users, broken back behavior, and deep-link bugs. Use canonical patterns and respect platform conventions.

### 1. Primary Navigation Shapes

| Shape | Intent | Notes |
| --- | --- | --- |
| Stack | Drill into detail and return | Default on both platforms |
| Tab | 2-5 peer destinations | Bottom on both platforms in 2026 |
| Drawer | Many secondary destinations | Common on Android, rarer on iOS |
| Modal | Self-contained task | Present, cancel, done |
| Nested (tabs of stacks) | App shell | Each tab owns its own stack |
| Wizard | Linear multi-step flow | Explicit progress, cancelable |

### 2. Stack Navigation

Stack navigation is push/pop. The back button (hardware on Android, swipe/chevron on iOS) must always work predictably.

```swift
// SwiftUI NavigationStack
NavigationStack(path: $path) {
    ArticleListView()
        .navigationDestination(for: Article.self) { ArticleDetailView(article: $0) }
}
```

```kotlin
// Jetpack Navigation-Compose
NavHost(navController, startDestination = "list") {
    composable("list") { ArticleListScreen(onOpen = { id -> navController.navigate("detail/$id") }) }
    composable("detail/{id}") { backStack ->
        ArticleDetailScreen(id = backStack.arguments?.getString("id")!!)
    }
}
```

```dart
// Flutter go_router
final router = GoRouter(routes: [
  GoRoute(path: '/', builder: (_, __) => const ArticleListScreen()),
  GoRoute(path: '/article/:id', builder: (_, s) => ArticleDetailScreen(id: s.pathParameters['id']!)),
]);
```

```tsx
// React Navigation
const Stack = createNativeStackNavigator();
<Stack.Navigator>
  <Stack.Screen name="List" component={ArticleList} />
  <Stack.Screen name="Detail" component={ArticleDetail} />
</Stack.Navigator>
```

### 3. Tab Navigation

Each tab owns its own stack. Switching tabs does not reset the other tabs. Deep links restore state into the correct tab.

- iOS: `TabView`, `UITabBarController`.
- Android: `NavigationBar` (Material 3), `BottomNavigationView`.
- Flutter: `NavigationBar`, `go_router` `StatefulShellRoute`.
- RN: `@react-navigation/bottom-tabs`.

### 4. Modal Navigation

Use modals for tasks that the user can cancel. They cover the current context and return the user exactly where they were.

- Full-screen modal: long flows (checkout).
- Half-sheet modal: quick input (filter, compose).
- Alert/dialog: destructive confirmation.

Every modal has an explicit dismiss and a save/confirm action. Background taps may dismiss on iOS sheets; prevent data loss by auto-saving drafts.

### 5. Drawer Navigation

A drawer holds secondary destinations. It is rarely the primary shell on iOS. Prefer tabs for top destinations and drawer for utility (settings, help, sign out) only when tabs are insufficient.

### 6. Nested Flows

The most common mobile shell is **tabs of stacks**. A deep link to `/orders/42` opens the Orders tab and pushes the order detail. Stateful shell routes in go_router, nested navigators in React Navigation, and stacked `NavHost`s in Compose all express this.

### 7. Back Behavior Contract

- **Android hardware back** must always do the right thing. Intercept only when the screen has unsaved work, and then show a confirmation.
- **iOS swipe-back** must not break the navigation stack. Do not disable it without reason.
- **Root back** exits to the home screen on Android and is typically a no-op on iOS.
- **Deep-link back** should walk a sensible synthetic back stack (e.g., Detail -> List -> Home).

### 8. Deep Links and Restoration

Navigation routes must be expressible as URLs (or structured intents). That is the foundation for:

- Universal Links / App Links (see `lifecycle/deep-links-universal-links`).
- Push notifications opening specific screens.
- State restoration after process death.

Agents should avoid screen-only navigation that cannot be expressed as a route.

### 9. Transition and Motion

- Stack pushes slide horizontally (platform default).
- Tab switches do not animate content.
- Modal present slides up (iOS) or fades (Android Material).
- Do not custom-animate without a product reason; it breaks the muscle memory of the platform.

### 10. Anti-Patterns

- Hidden navigation (gestures with no visible entry).
- Drawers that hide the primary app function.
- Tabs that change based on state (the bar shape flickers).
- Modals stacked three deep.
- Back button that navigates forward.
- Deep links that do not establish a back stack.

### 11. Cross-Platform Adaptive Navigation

Use adaptive navigation helpers so the same code produces platform-correct chrome.

```dart
// Flutter adaptive
PlatformScaffold(
  appBar: PlatformAppBar(title: const Text('Home')),
  body: const HomeBody(),
);
```

```tsx
// RN: platform-specific headers via options
<Stack.Screen
  name="Home"
  component={Home}
  options={Platform.select({
    ios: { headerLargeTitle: true },
    android: { headerTitleAlign: 'left' },
  })}
/>
```

## Checklist

- [ ] Primary shell is named (tabs, drawer, stack only, or wizard).
- [ ] Each tab owns its own stack; deep links restore into the correct tab.
- [ ] Every route is URL-expressible for deep linking and restoration.
- [ ] Back behavior is explicit, including unsaved-work interception.
- [ ] Modals have explicit cancel and confirm; drafts are preserved.
- [ ] Transitions follow platform defaults unless a product reason is documented.
- [ ] Drawer is used only for secondary destinations.
- [ ] Adaptive components are used in cross-platform stacks.

