Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
thebushidocollective avatar

React Native Navigation

  • 1 installs
  • 186 repo stars
  • Updated July 19, 2026
  • thebushidocollective/han

Implement React Native navigation with React Navigation, including stack, tab, drawer navigation, and deep linking.

About

Covers implementing navigation in React Native apps with React Navigation, including stack, tab, and drawer navigation and deep linking. A developer uses it when wiring screen navigation into a React Native app.

  • Stack, tab, and drawer navigation
  • Deep linking and navigation patterns

React Native Navigation by the numbers

  • 1 all-time installs (skills.sh)
  • Ranked #959 of 1,039 Mobile Development skills by installs in the Skillselion catalog
  • Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thebushidocollective/han --skill react-native-navigation

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs1
repo stars186
Last updatedJuly 19, 2026
Repositorythebushidocollective/han

What it does

Implement React Native navigation with React Navigation, including stack, tab, drawer navigation, and deep linking.

Files

SKILL.mdMarkdownGitHub ↗

React Native Navigation

Use this skill when implementing navigation in React Native applications using React Navigation (the de facto standard navigation library).

Key Concepts

Installation

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

Basic Setup

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>
  );
}

Stack Navigation

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>
  );
}

Tab Navigation

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>
  );
}

Best Practices

Type-Safe Navigation

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 />;
}

Header Customization

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>

Dynamic Header Options

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 />;
}

Nested Navigators

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>
  );
}

Common Patterns

Authentication Flow

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>
  );
}

Deep Linking

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>
  );
}

Modal Navigation

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>

Navigation Guards

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>;
}

Custom Tab Bar

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>

Anti-Patterns

Don't Navigate in useEffect Without Dependencies

// Bad - Infinite loop risk
useEffect(() => {
  navigation.navigate('Home');
});

// Good - Proper dependencies
useEffect(() => {
  if (shouldNavigate) {
    navigation.navigate('Home');
  }
}, [shouldNavigate, navigation]);

Don't Use navigate() for Replacing Screens

// Bad - Adds to navigation stack
navigation.navigate('SignIn');

// Good - Replaces current screen
navigation.replace('SignIn');

Don't Access Navigation Without Type Safety

// 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
}

Don't Forget to Handle Back Button on Android

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 />;
}

Related Skills

  • react-native-components: Building UI components for screens
  • react-native-platform: Platform-specific navigation behavior
  • react-native-performance: Optimizing navigation performance

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.