From react-native
Implements stack, tab, drawer navigation in React Native apps using React Navigation. Covers installation, setup, deep linking, and navigation patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/react-native:react-native-navigationThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill when implementing navigation in React Native applications using React Navigation (the de facto standard navigation library).
Use this skill when implementing navigation in React Native applications using React Navigation (the de facto standard navigation library).
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
# For stack navigation
npm install @react-navigation/native-stack
# For tab navigation
npm install @react-navigation/bottom-tabs
# For drawer navigation
npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { itemId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
The most common navigation pattern:
import React from 'react';
import { View, Text, Button } from 'react-native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { itemId: string; title: string };
};
type HomeProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function HomeScreen({ navigation }: HomeProps) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() =>
navigation.navigate('Details', {
itemId: '123',
title: 'My Item',
})
}
/>
</View>
);
}
function DetailsScreen({ route, navigation }: DetailsProps) {
const { itemId, title } = route.params;
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details Screen</Text>
<Text>Item ID: {itemId}</Text>
<Text>Title: {title}</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
}
Bottom tabs for primary navigation:
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
type TabParamList = {
Home: undefined;
Search: undefined;
Profile: undefined;
};
const Tab = createBottomTabNavigator<TabParamList>();
export default function TabNavigator() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName: keyof typeof Ionicons.glyphMap;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'Search') {
iconName = focused ? 'search' : 'search-outline';
} else {
iconName = focused ? 'person' : 'person-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: '#007AFF',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Search" component={SearchScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
Define navigation types for type safety:
import { NativeStackScreenProps } from '@react-navigation/native-stack';
// Define param list
type RootStackParamList = {
Home: undefined;
Details: { itemId: string };
UserProfile: { userId: string; name: string };
};
// Declare global types
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
// Use typed props
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function DetailsScreen({ route, navigation }: DetailsProps) {
// route.params is fully typed
const { itemId } = route.params;
// navigation.navigate is type-safe
navigation.navigate('UserProfile', {
userId: '123',
name: 'John',
});
return <View />;
}
Customize navigation headers:
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: '#007AFF',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'My Home',
headerRight: () => (
<Button
onPress={() => console.log('Pressed')}
title="Info"
color="#fff"
/>
),
}}
/>
</Stack.Navigator>
Set header options from screen:
import { useLayoutEffect } from 'react';
function DetailsScreen({ navigation, route }: DetailsProps) {
useLayoutEffect(() => {
navigation.setOptions({
title: route.params.title,
headerRight: () => (
<Button title="Save" onPress={() => console.log('Save')} />
),
});
}, [navigation, route.params.title]);
return <View />;
}
Combine different navigation patterns:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const HomeStack = createNativeStackNavigator();
const ProfileStack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
function ProfileStackScreen() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} />
<ProfileStack.Screen name="Settings" component={SettingsScreen} />
</ProfileStack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStackScreen} />
<Tab.Screen name="ProfileTab" component={ProfileStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
import React, { useState } from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
SignIn: undefined;
SignUp: undefined;
Home: undefined;
Details: { itemId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
const [isSignedIn, setIsSignedIn] = useState(false);
return (
<NavigationContainer>
<Stack.Navigator>
{!isSignedIn ? (
// Auth screens
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
</>
) : (
// App screens
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
);
}
Configure deep linking:
import { NavigationContainer } from '@react-navigation/native';
const linking = {
prefixes: ['myapp://', 'https://myapp.com'],
config: {
screens: {
Home: 'home',
Details: 'details/:itemId',
UserProfile: 'user/:userId',
},
},
};
export default function App() {
return (
<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="UserProfile" component={UserProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Present screens as modals:
<Stack.Navigator>
<Stack.Group>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Group>
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="CreatePost" component={CreatePostScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Group>
</Stack.Navigator>
Protect routes with guards:
import { useEffect } from 'react';
function ProtectedScreen({ navigation }: any) {
const isAuthenticated = useAuth(); // Custom hook
useEffect(() => {
if (!isAuthenticated) {
navigation.replace('SignIn');
}
}, [isAuthenticated, navigation]);
if (!isAuthenticated) {
return null; // Or loading screen
}
return <View>{/* Protected content */}</View>;
}
Create custom tab bar:
import { View, Text, TouchableOpacity } from 'react-native';
function CustomTabBar({ state, descriptors, navigation }: any) {
return (
<View style={{ flexDirection: 'row', height: 60 }}>
{state.routes.map((route: any, index: number) => {
const { options } = descriptors[route.key];
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
return (
<TouchableOpacity
key={route.key}
onPress={onPress}
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: isFocused ? '#007AFF' : '#fff',
}}
>
<Text style={{ color: isFocused ? '#fff' : '#000' }}>
{options.title || route.name}
</Text>
</TouchableOpacity>
);
})}
</View>
);
}
<Tab.Navigator tabBar={(props) => <CustomTabBar {...props} />}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
// Bad - Infinite loop risk
useEffect(() => {
navigation.navigate('Home');
});
// Good - Proper dependencies
useEffect(() => {
if (shouldNavigate) {
navigation.navigate('Home');
}
}, [shouldNavigate, navigation]);
// Bad - Adds to navigation stack
navigation.navigate('SignIn');
// Good - Replaces current screen
navigation.replace('SignIn');
// Bad - No type safety
function MyScreen({ navigation }: any) {
navigation.navigate('Detials', { itemId: 123 }); // Typo won't be caught
}
// Good - Type-safe navigation
type Props = NativeStackScreenProps<RootStackParamList, 'Home'>;
function MyScreen({ navigation }: Props) {
navigation.navigate('Details', { itemId: '123' }); // Type-checked
}
import { useEffect } from 'react';
import { BackHandler } from 'react-native';
function MyScreen({ navigation }: any) {
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
() => {
navigation.goBack();
return true; // Prevent default behavior
}
);
return () => backHandler.remove();
}, [navigation]);
return <View />;
}
npx claudepluginhub thebushidocollective/han --plugin react-nativeSets up navigation structure for React Native apps: tab bars, stack navigators, drawer menus, deep linking, and type-safe parameters using Expo Router or React Navigation.
Provides navigation patterns for React Native Web using React Navigation, including stack/tab navigators, type-safe params, deep linking, and web URLs. Use for cross-platform routing.
React Navigation patterns for mobile apps including stack, tab, drawer navigators, deep linking, and typed navigation with TypeScript. Use when building navigation structure, handling deep links, or implementing authentication flows.