agents-inc/skills/src/skills/mobile-navigation-react-navigation/SKILL.md
mobile-navigation-react-navigation
React Navigation 7+ patterns - static and dynamic APIs, type-safe navigation, stack/tab/drawer navigators, deep linking, authentication flows, screen preloading, header customization
- Source repository stars
- 23
- Declared platforms
- 0
- Static risk flags
- 1
- Last source update
- 2026-08-09
- Source checked
- 2026-08-28
Decision brief
What it does: where it fits
Quick Guide: Use the static API for simpler TypeScript inference and automatic deep linking config. Use the dynamic API when you need runtime-dynamic screen lists. Always declare a global RootParamList for type-safe useNavigation everywhere. Use createNativeStackNavigator (not t…
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-navigation-react-navigation"Inspect the Agent Skill "mobile-navigation-react-navigation" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/mobile-navigation-react-navigation/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Pattern 1: Static API Setup
The static API uses object configuration for simpler TypeScript and automatic deep linking.
The static API uses object configuration for simpler TypeScript and automatic deep linking.Why good: types inferred from config (no manual ParamList), deep linking paths defined per-screen, less boilerplate than dynamic APISee examples/core.md for complete static API setup with groups and conditional screens. - 02
Pattern 2: Dynamic API Setup
The dynamic API uses JSX components. Use when screen lists are runtime-dynamic.
The dynamic API uses JSX components. Use when screen lists are runtime-dynamic.Why good: familiar JSX pattern, supports runtime-dynamic screen lists, manual param list gives explicit controlSee examples/core.md for dynamic API with typed hooks and nested navigators. - 03
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
Setting up navigation structure (stack, tab, drawer) in a React Native appChoosing between static API and dynamic API for navigator configurationAdding type-safe navigation with TypeScript (param lists, typed hooks) - 04
Philosophy
React Navigation provides routing and navigation for React Native apps. The key decision in v7 is static vs dynamic API:
Static API -- object-based configuration. Simpler TypeScript (types inferred from config), automatic deep linking path generation, less boilerplate. Use for most apps.Dynamic API -- component-based configuration (/). Required when screen lists change at runtime or you need full programmatic control over navigator props. More verbose but more flexible.Native stack by default -- createNativeStackNavigator uses platform navigation primitives (UINavigationController/Fragment) for smoother transitions and lower memory. The JS stack (@react-navigation/stack) only when you… - 05
Core Patterns
The static API uses object configuration for simpler TypeScript and automatic deep linking.
The static API uses object configuration for simpler TypeScript and automatic deep linking.Why good: types inferred from config (no manual ParamList), deep linking paths defined per-screen, less boilerplate than dynamic APISee examples/core.md for complete static API setup with groups and conditional screens.
Permission review
Static risk signals and limitations
Network access
The documentation includes network, browsing, or remote request actions.
linking={{ prefixes: ["myapp://", "https://myapp.com"] }}Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 23 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- agents-inc/skills
- Skill path
- src/skills/mobile-navigation-react-navigation/SKILL.md
- Commit
- 81d43a51211aca12c85dcc16085fa99014ec548e
- License
- MIT
- Collected
- 2026-08-28
- Default branch
- main
View the original SKILL.md
React Navigation Patterns
Quick Guide: Use the static API for simpler TypeScript inference and automatic deep linking config. Use the dynamic API when you need runtime-dynamic screen lists. Always declare a global
RootParamListfor type-safeuseNavigationeverywhere. UsecreateNativeStackNavigator(not the JS stack) for production performance. Auth flows use conditional screen rendering via theifcallback (static) or conditional JSX (dynamic). Deep linking config lives per-screen in the static API -- no separate config object needed.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST declare a global ReactNavigation.RootParamList interface so useNavigation is type-safe without manual annotation)
(You MUST use createNativeStackNavigator for production apps -- the JS stack (@react-navigation/stack) is significantly slower and only needed for highly custom transitions)
(You MUST use popTo() to navigate back to a previous screen in the stack -- navigate() in v7 no longer pops back to existing screens)
(You MUST wrap useFocusEffect callbacks in useCallback -- without it, the effect runs on every render, not just focus changes)
(You MUST NOT use navigation.navigate('NestedScreen') to reach screens in child navigators -- v7 removed implicit nested navigation; use explicit parent targeting)
</critical_requirements>
Auto-detection: React Navigation, @react-navigation, createNativeStackNavigator, createBottomTabNavigator, createDrawerNavigator, createStaticNavigation, NavigationContainer, useNavigation, useRoute, useFocusEffect, usePreventRemove, StaticParamList, StaticScreenProps, NativeStackNavigationProp, CompositeNavigationProp, NavigatorScreenParams, deep linking, linking config, headerSearchBarOptions, headerLargeTitle, popTo, preload
When to use:
- Setting up navigation structure (stack, tab, drawer) in a React Native app
- Choosing between static API and dynamic API for navigator configuration
- Adding type-safe navigation with TypeScript (param lists, typed hooks)
- Configuring deep linking (URL prefixes, path params, universal links)
- Implementing authentication flows with conditional screen rendering
- Customizing headers (large titles, search bars, custom buttons)
- Preloading screens for perceived performance
- Preventing back navigation for unsaved changes
When NOT to use:
- File-based routing with a managed workflow (uses its own router built on React Navigation)
- Web-only React apps (use a web router)
- Simple single-screen apps with no navigation
Key patterns covered:
- Static API vs dynamic API: when to use each
- Global
RootParamListdeclaration for type-safe hooks everywhere - Native stack vs JS stack performance trade-offs
- Auth flow with conditional screens (static
ifcallback or dynamic JSX) - Deep linking configuration (per-screen in static,
linkingprop in dynamic) - Screen preloading with
navigation.preload() useFocusEffectfor screen lifecycle managementusePreventRemovefor unsaved changes guards- Header customization: large titles, search bars, form sheets
Detailed Resources:
- examples/core.md - Static API setup, dynamic API setup, type-safe navigation, global RootParamList
- examples/patterns.md - Auth flows, deep linking, modals, tab navigator with nested stacks
- examples/advanced.md - Screen preloading, state persistence, usePreventRemove, useFocusEffect, header customization
- reference.md - Decision frameworks, screen options cheat sheet, v6-to-v7 migration
Philosophy
React Navigation provides routing and navigation for React Native apps. The key decision in v7 is static vs dynamic API:
- Static API -- object-based configuration. Simpler TypeScript (types inferred from config), automatic deep linking path generation, less boilerplate. Use for most apps.
- Dynamic API -- component-based configuration (
<Stack.Navigator>/<Stack.Screen>). Required when screen lists change at runtime or you need full programmatic control over navigator props. More verbose but more flexible.
Both APIs produce the same navigation behavior -- the difference is configuration ergonomics.
Core principles:
- Native stack by default --
createNativeStackNavigatoruses platform navigation primitives (UINavigationController/Fragment) for smoother transitions and lower memory. The JS stack (@react-navigation/stack) only when you need custom transition animations not available natively. - Type safety from the root -- Declare
ReactNavigation.RootParamListglobally so everyuseNavigation()call is type-checked without manual generics. - Deep linking as first-class -- Configure linking per-screen (static API) or in a centralized config (dynamic API). Prefixes handle custom schemes and universal links.
- Screen lifecycle via focus -- Screens in a stack remain mounted when covered. Use
useFocusEffect(notuseEffect) for work that should pause when the screen loses focus.
v7 behavioral changes from v6:
navigate()no longer pops back to existing screens -- usepopTo()instead- Implicit nested navigator navigation removed -- must target parent screen explicitly
headerBackTitleVisiblereplaced withheaderBackButtonDisplayMode- Navigation state is frozen in dev mode (mutations throw)
- Theme objects now require a
fontsproperty
Core Patterns
Pattern 1: Static API Setup
The static API uses object configuration for simpler TypeScript and automatic deep linking.
import { createStaticNavigation } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import type { StaticParamList } from "@react-navigation/native";
const RootStack = createNativeStackNavigator({
initialRouteName: "Home",
screenOptions: { headerShown: true },
screens: {
Home: HomeScreen,
Profile: {
screen: ProfileScreen,
linking: "profile/:userId",
},
},
});
const Navigation = createStaticNavigation(RootStack);
// Declare global types -- makes useNavigation() type-safe everywhere
type RootStackParamList = StaticParamList<typeof RootStack>;
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
export function App() {
return <Navigation />;
}
Why good: types inferred from config (no manual ParamList), deep linking paths defined per-screen, less boilerplate than dynamic API
See examples/core.md for complete static API setup with groups and conditional screens.
Pattern 2: Dynamic API Setup
The dynamic API uses JSX components. Use when screen lists are runtime-dynamic.
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
};
// Must declare globally for type-safe useNavigation()
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
const Stack = createNativeStackNavigator<RootStackParamList>();
export function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Why good: familiar JSX pattern, supports runtime-dynamic screen lists, manual param list gives explicit control
See examples/core.md for dynamic API with typed hooks and nested navigators.
Pattern 3: Type-Safe Navigation Hooks
Declare RootParamList globally once, then useNavigation() and useRoute() are type-safe everywhere without manual generics.
// In any screen component -- no generic needed
function HomeScreen() {
const navigation = useNavigation();
// Type-checked: "Profile" must exist, params must match
navigation.navigate("Profile", { userId: "123" });
// Type error: "Nonexistent" is not in RootParamList
navigation.navigate("Nonexistent"); // compile error
}
For nested navigators, use CompositeScreenProps or NavigatorScreenParams to propagate types. With the static API, use StaticScreenProps for screen component props.
See examples/core.md for composite types and StaticScreenProps.
Pattern 4: Authentication Flow
Conditionally render auth or main screens. React Navigation animates the transition automatically.
// Static API: use the `if` callback on groups
const useIsAuthenticated = () => {
const { isAuthenticated } = useContext(AuthContext);
return isAuthenticated;
};
const useIsGuest = () => !useIsAuthenticated();
const RootStack = createNativeStackNavigator({
screens: {},
groups: {
Auth: {
if: useIsGuest,
screenOptions: { headerShown: false },
screens: { Login: LoginScreen, Register: RegisterScreen },
},
Main: {
if: useIsAuthenticated,
screens: { Home: HomeScreen, Profile: ProfileScreen },
},
},
});
Why good: if callbacks cleanly separate auth/main screens, React Navigation handles transition animation, no manual state-based conditional rendering needed
See examples/patterns.md for both static and dynamic auth flow implementations.
Pattern 5: Deep Linking
Static API: define linking per-screen. Dynamic API: pass a linking config to NavigationContainer.
// Static API -- linking defined inline per screen
const RootStack = createNativeStackNavigator({
screens: {
Home: { screen: HomeScreen, linking: "" },
Profile: {
screen: ProfileScreen,
linking: {
path: "user/:userId",
parse: { userId: (id: string) => id.replace(/^@/, "") },
stringify: { userId: (id: string) => `@${id}` },
},
},
},
});
const Navigation = createStaticNavigation(RootStack);
export function App() {
return (
<Navigation
linking={{ prefixes: ["myapp://", "https://myapp.com"] }}
/>
);
}
Why good: linking config co-located with screen definition, parse/stringify handle URL encoding, prefixes handle both custom scheme and universal links
See examples/patterns.md for dynamic API linking, custom URL handlers, and platform-specific setup.
Pattern 6: Native Stack vs JS Stack
Which stack navigator?
|-- Need custom JS-driven transition animations? --> @react-navigation/stack (JS)
|-- Everything else --> @react-navigation/native-stack (NATIVE)
| Feature | Native Stack | JS Stack |
|---|---|---|
| Performance | Native animations, lower memory | JS-driven, higher overhead |
| Transitions | Platform defaults + limited custom | Fully customizable |
| Large titles (iOS) | Supported natively | Not available |
| Search bar (iOS) | headerSearchBarOptions | Must build custom |
| Form sheets | presentation: "formSheet" | Not available |
| Gesture handling | Native, smooth | JS-driven |
Default to native stack. Only use JS stack when you need transition animations that native stack cannot provide.
Pattern 7: useFocusEffect for Screen Lifecycle
Screens in a stack remain mounted when a new screen is pushed. Use useFocusEffect to run effects only when the screen is focused.
import { useCallback } from "react";
import { useFocusEffect } from "@react-navigation/native";
function ChatScreen({ roomId }: { roomId: string }) {
useFocusEffect(
useCallback(() => {
const ws = new WebSocket(`wss://chat.example.com/rooms/${roomId}`);
// Cleanup runs when screen loses focus
return () => ws.close();
}, [roomId]),
);
}
Gotcha: The callback MUST be wrapped in useCallback. Without it, the effect re-runs on every render, not just focus changes.
See examples/advanced.md for polling, analytics tracking, and resource cleanup patterns.
Pattern 8: Screen Preloading
Preload heavy screens before the user navigates to them. The screen is rendered off-screen with all hooks running.
function ProductList() {
const navigation = useNavigation();
const handleLongPress = (productId: string) => {
navigation.preload("ProductDetail", { productId });
};
// Later: navigation.navigate("ProductDetail", { productId }) is instant
}
Limitations: Preloaded screens cannot dispatch navigation actions, update options, or listen to events until actually navigated to.
Pattern 9: Header Customization
Native stack supports platform-native header features: large titles, search bars, and form sheets.
<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{
headerLargeTitleEnabled: true,
headerLargeStyle: { backgroundColor: "#f5f5f5" },
headerSearchBarOptions: {
placeholder: "Search settings...",
onChangeText: (e) => handleSearch(e.nativeEvent.text),
hideWhenScrolling: true,
},
}}
/>
Gotcha: Custom header functions disable ALL native header features (large title, search bar, blur effects). Use headerLeft/headerRight to add custom elements while keeping native behavior.
See examples/advanced.md for form sheets, custom header items, and search bar integration.
<decision_framework>
Decision Framework
Static vs Dynamic API
Starting a new navigation setup?
|-- Can all screens be defined at build time?
| |-- YES --> Static API (simpler TS, auto deep linking)
| +-- NO --> Dynamic API (runtime screen lists)
|
|-- Migrating incrementally from v6?
| +-- YES --> Dynamic API at root, static for new navigators
| (use getComponent() and createPathConfigForStaticNavigation)
|
|-- Need to wrap navigator with providers (e.g. context)?
| +-- Use static API with .with() method
Navigator Type
What navigation pattern?
|-- Linear flow (onboarding, checkout) --> Stack Navigator
|-- Main app sections with persistent bar --> Bottom Tab Navigator
|-- Side menu / settings panel --> Drawer Navigator
|-- Modal overlays --> Stack with presentation: "modal"
|-- Bottom sheets --> Stack with presentation: "formSheet"
|-- Combination --> Nest navigators (tabs inside stack, stacks inside tabs)
Navigation Method
How to move between screens?
|-- Push new screen forward --> navigation.navigate("Screen", params)
|-- Go back to specific screen --> navigation.popTo("Screen", params)
|-- Go back one screen --> navigation.goBack()
|-- Replace current screen --> navigation.replace("Screen", params)
|-- Reset entire stack --> navigation.reset({ routes: [...] })
|-- Navigate to nested screen --> navigation.navigate("Parent", { screen: "Child" })
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Using
navigate()to go back to a previous screen -- v7 changed behavior;navigate()stays on current screen if target exists. UsepopTo()instead. - Using
navigation.navigate("NestedScreen")to reach child navigator screens -- removed in v7. Must usenavigate("ParentScreen", { screen: "NestedScreen" }). - Using JS stack (
@react-navigation/stack) for production without a specific need for custom transitions -- native stack is significantly more performant. - Missing global
RootParamListdeclaration -- everyuseNavigation()call is untyped, losing the primary benefit of TypeScript with React Navigation. - Using a custom
headerfunction and expecting native features (large title, search bar, blur) -- custom headers disable all native header functionality.
Medium Priority Issues:
- Inline component functions in
<Stack.Screen component={() => <MyScreen />} />-- creates a new component on every render, causing unmount/remount. Always pass a reference. - Not using
useFocusEffectfor screen-specific side effects --useEffectruns even when the screen is covered by another screen in the stack. - Mutating navigation state directly (caught in dev mode in v7, silent corruption in prod).
- Missing
fontsproperty in custom theme -- required in v7, crashes without it.
Gotchas & Edge Cases:
useFocusEffectcallback must be wrapped inuseCallback-- without it, the effect fires on every render, not just focus changesusePreventRemoveonly fires for navigation state removal (back, pop, reset) -- it does NOT fire when the screen is merely unfocused (push, tab switch)- Preloaded screens cannot dispatch navigation actions or call
navigation.setOptions()until actually navigated to - Screen
optionscan be an object or a function receiving{ route, navigation }-- use the function form when options depend on route params headerSearchBarOptionsrequirescontentInsetAdjustmentBehavior="automatic"on your ScrollView/FlatList for proper layoutheaderBackButtonDisplayModereplacedheaderBackTitleVisiblein v7 -- values are "default", "generic", or "minimal"unmountOnBlurremoved from tabs/drawer in v7 -- usepopToTopOnBlur: trueor theuseIsFocusedpattern instead- Navigation state frozen in dev mode -- if you were mutating state directly, you'll get runtime errors in v7 dev builds
- Android requires
RNScreensFragmentFactorysetup inMainActivity-- without it, View state is lost during Activity restarts - The
Linkcomponent changed from path-based to screen-based:<Link screen="Profile" params={{ userId }}>not<Link to="/profile/123">
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST declare a global ReactNavigation.RootParamList interface so useNavigation is type-safe without manual annotation)
(You MUST use createNativeStackNavigator for production apps -- the JS stack (@react-navigation/stack) is significantly slower and only needed for highly custom transitions)
(You MUST use popTo() to navigate back to a previous screen in the stack -- navigate() in v7 no longer pops back to existing screens)
(You MUST wrap useFocusEffect callbacks in useCallback -- without it, the effect runs on every render, not just focus changes)
(You MUST NOT use navigation.navigate('NestedScreen') to reach screens in child navigators -- v7 removed implicit nested navigation; use explicit parent targeting)
Failure to follow these rules will cause untyped navigation, performance issues, broken back navigation, and runtime errors.
</critical_reminders>
Frequently asked questions
What to verify before installation and use
What does the mobile-navigation-react-navigation source document cover?
Quick Guide: Use the static API for simpler TypeScript inference and automatic deep linking config. Use the dynamic API when you need runtime-dynamic screen lists. Always declare a global RootParamList for type-safe useNavigation everywhere. Use createNativeStackNavigator (not t…
How do I install mobile-navigation-react-navigation?
The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/mobile-navigation-react-navigation". Inspect the command and pinned source before running it.
Which permission-related actions were detected?
Static rules flagged network in the source; the page lists the matching lines and excerpts.
Alternatives
Compare before choosing
event4u-app/agent-config
existing-ui-audit
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.
UiPath/skills
uipath-coded-apps
UiPath Coded Apps — scaffold, build, run, and deploy Coded Web Apps and Coded Action Apps: React/TypeScript apps that call UiPath Cloud APIs via the `@uipath/uipath-typescript` SDK and ship to Automation Cloud (push/pull to Studio Web, pack, publish, deploy, OAuth-PKCE). Also generates live analytics & governance dashboards from a plain-language request, wired to tenant data via the Insights real-time API, with edit and deploy flows. For RPA→uipath-rpa, Python agents→uipath-agents, Maestro flows
fcakyon/claude-codex-settings
vercel-react-view-transitions
Guide for implementing smooth, native-feeling animations using React's View Transition API (`<ViewTransition>` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view
yonatangross/orchestkit
json-render-catalog
json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.