From react-native-web
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.
npx claudepluginhub thebushidocollective/han --plugin react-native-webThis skill is limited to using the following tools:
Navigation patterns for React Native Web using React Navigation, supporting both native and web platforms with a unified API.
Implements stack, tab, drawer navigation in React Native apps using React Navigation. Covers installation, setup, deep linking, and navigation patterns.
Provides core concepts, components, platform abstraction, and best practices for React Native Web projects to build cross-platform web and native apps.
Guides React Native development for cross-platform iOS/Android apps, covering components, navigation, native modules, platform-specific code, and performance optimization.
Share bugs, ideas, or general feedback.
Navigation patterns for React Native Web using React Navigation, supporting both native and web platforms with a unified API.
React Navigation is the standard navigation library for React Native and React Native Web:
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
export function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Define navigation types for type safety:
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Details: { id: string; title: string };
Profile: { userId: string };
};
type HomeProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
type DetailsProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function HomeScreen({ navigation }: HomeProps) {
return (
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details', { id: '123', title: 'Item' })}
/>
);
}
React Navigation automatically handles URLs on web:
import { LinkingOptions } from '@react-navigation/native';
const linking: LinkingOptions<RootStackParamList> = {
prefixes: ['https://myapp.com', 'myapp://'],
config: {
screens: {
Home: '',
Details: 'details/:id',
Profile: 'profile/:userId',
},
},
};
<NavigationContainer linking={linking}>
{/* Navigator */}
</NavigationContainer>
✅ Use for screen-to-screen navigation:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator<RootStackParamList>();
function RootNavigator() {
return (
<Stack.Navigator
screenOptions={{
headerShown: true,
headerStyle: {
backgroundColor: '#007AFF',
},
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Home' }}
/>
<Stack.Screen
name="Details"
component={DetailsScreen}
options={({ route }) => ({ title: route.params.title })}
/>
</Stack.Navigator>
);
}
✅ Use for main app sections:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
const Tab = createBottomTabNavigator<TabParamList>();
function TabNavigator() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
const iconName = route.name === 'Home' ? 'home' : 'person';
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: '#007AFF',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
✅ Use for sidebar navigation on web:
import { createDrawerNavigator } from '@react-navigation/drawer';
import { useWindowDimensions } from 'react-native';
const Drawer = createDrawerNavigator();
function DrawerNavigator() {
const { width } = useWindowDimensions();
const isLargeScreen = width >= 768;
return (
<Drawer.Navigator
screenOptions={{
drawerType: isLargeScreen ? 'permanent' : 'front',
drawerStyle: {
width: 240,
},
}}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Settings" component={SettingsScreen} />
</Drawer.Navigator>
);
}
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
type RootStackParamList = {
Tabs: undefined;
Details: { id: string };
Modal: undefined;
};
type TabParamList = {
Home: undefined;
Search: undefined;
Profile: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
const Tab = createBottomTabNavigator<TabParamList>();
function TabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Search" component={SearchScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
export function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Tabs"
component={TabNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen
name="Modal"
component={ModalScreen}
options={{ presentation: 'modal' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
import { useNavigation, useRoute } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import type { RouteProp } from '@react-navigation/native';
type DetailsScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Details'
>;
type DetailsScreenRouteProp = RouteProp<RootStackParamList, 'Details'>;
function DetailsScreen() {
const navigation = useNavigation<DetailsScreenNavigationProp>();
const route = useRoute<DetailsScreenRouteProp>();
const { id, title } = route.params;
return (
<View>
<Text>{title}</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
<Button
title="Go to Profile"
onPress={() => navigation.navigate('Profile', { userId: id })}
/>
</View>
);
}
import { LinkingOptions } from '@react-navigation/native';
const linking: LinkingOptions<RootStackParamList> = {
prefixes: ['https://myapp.com', 'myapp://'],
config: {
screens: {
Tabs: {
screens: {
Home: '',
Search: 'search',
Profile: 'profile',
},
},
Details: 'details/:id',
Modal: 'modal',
},
},
};
export function App() {
return (
<NavigationContainer linking={linking} fallback={<LoadingScreen />}>
{/* Navigator */}
</NavigationContainer>
);
}
import { useAuth } from './auth-context';
function RootNavigator() {
const { isAuthenticated } = useAuth();
return (
<Stack.Navigator>
{isAuthenticated ? (
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</>
) : (
<>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
</>
)}
</Stack.Navigator>
);
}
import { useNavigation } from '@react-navigation/native';
import { useEffect } from 'react';
function ProtectedScreen() {
const navigation = useNavigation();
const { isAuthenticated } = useAuth();
useEffect(() => {
if (!isAuthenticated) {
navigation.navigate('Login');
}
}, [isAuthenticated, navigation]);
if (!isAuthenticated) {
return null;
}
return <View>{/* Protected content */}</View>;
}
import { createNavigationContainerRef } from '@react-navigation/native';
// Create ref outside component
export const navigationRef = createNavigationContainerRef<RootStackParamList>();
// Use in App component
export function App() {
return (
<NavigationContainer ref={navigationRef}>
{/* Navigator */}
</NavigationContainer>
);
}
// Navigate from anywhere
export function navigateToDetails(id: string) {
if (navigationRef.isReady()) {
navigationRef.navigate('Details', { id });
}
}
❌ Don't use React Router directly (use React Navigation):
// Bad - React Router is web-only
import { BrowserRouter, Route } from 'react-router-dom';
// Good - React Navigation works everywhere
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
❌ Don't pass navigation prop manually:
// Bad
<ChildComponent navigation={navigation} />
// Good - use useNavigation hook
function ChildComponent() {
const navigation = useNavigation();
// ...
}
❌ Don't store navigation state in Redux/Context:
// Bad - navigation state should be managed by React Navigation
const [currentScreen, setCurrentScreen] = useState('Home');
// Good - let React Navigation manage state
// Use navigation listeners if you need to react to changes