Mastering Bottom Sheets in React Native with Expo Router

Bottom sheets have become a popular UI pattern in mobile applications, offering a user-friendly way to present contextual information or actions. If you’re developing a React Native app with Expo Router and want to incorporate bottom sheets, the gorhom/react-native-bottom-sheet library is an excellent choice. This post guides you through two effective strategies for integrating route-based bottom sheets into your Expo Router project.

Why Use Route-Based Bottom Sheets?

Leveraging Expo Router’s built-in navigation for bottom sheets offers several advantages:

  • Simplified State Management: You avoid manually managing the bottom sheet’s visibility state (open/closed) using methods like present, dismiss, or snapToIndex. The router handles this automatically.
  • Clean URL Structure: Each bottom sheet can have its own unique route, making it easy to deep link and share specific content within your app.
  • Consistent Navigation: Bottom sheets integrate seamlessly with the overall navigation flow of your application.

Approach 1: Single Bottom Sheet with Nested Routes

This approach is ideal for scenarios where you have a primary bottom sheet that houses multiple related screens or steps. Think of it like a mini-navigation stack within the bottom sheet.

Key Concepts:

  • Transparent Modal: A top-level screen is defined as a transparentModal. This ensures the bottom sheet overlays the existing content, maintaining the visual context of the underlying screen.
  • Nested Stack: Inside the bottom sheet’s layout, a Stack component from Expo Router manages the navigation between the different screens within the bottom sheet.

Implementation Steps:

  1. Create a Transparent Screen: In your main app layout (app/_layout.tsx), define a screen with the presentation option set to "transparentModal". Disable the default screen animation because the bottom sheet provides its own.
    // app/_layout.tsx
    <Stack.Screen
        name="stackSheet"
        options={{
            headerShown: false,
            animation: "none",
            presentation: "transparentModal",
        }}
    />
    
  2. Bottom Sheet Layout: Create a layout file for your bottom sheet (app/stackSheet/_layout.tsx). The BottomSheet component should wrap the Stack. This layout also handles closing the bottom sheet when the user taps outside of it (using a backdrop). The snap points (how far the bottom sheet can be dragged) are also defined here.
    // app/stackSheet/_layout.tsx
    const Approach1Layout = () => {
        const router = useRouter();
        const snapPoints = useMemo(() => ["50%", "80%"], []);
    
        const renderBackdrop = useCallback((props: BottomSheetBackdropProps) => {
            return <BottomSheetBackdrop {...props} disappearsOnIndex={-1} opacity={0.35} />;
        }, []);
    
        return (
            <BottomSheet
                enableDynamicSizing={false}
                backdropComponent={renderBackdrop}
                snapPoints={snapPoints}
                onClose={() => router.dismissTo("/")} // Go back to the root route
            >
                <BottomSheetView style={styles.container}>
                    <Stack
                        initialRouteName="index"
                        screenOptions={{ contentStyle: { flex: 1, backgroundColor: "white" } }}
                    >
                        <Stack.Screen name="index" options={{ headerShown: false, headerTitle: "Approach 1" }} />
                        <Stack.Screen name="route1" options={{ headerTitle: "Route 1" }} />
                        <Stack.Screen name="route2" options={{ headerTitle: "Route 2" }} />
                        <Stack.Screen name="route3" options={{ headerTitle: "Route 3" }} />
                    </Stack>
                </BottomSheetView>
            </BottomSheet>
        );
    };
    
  3. Create Route Files: Add the individual route files (e.g., route1.tsx, route2.tsx, route3.tsx) inside the stackSheet directory. These represent the screens that will be displayed within the bottom sheet’s navigation stack.

  4. Navigation: To display the bottom sheet and navigate to a specific route within it, use a link like this: <Link href="/stackSheet/route1">.

Approach 2: Individual Route-Based Bottom Sheets

This method is best suited when you have distinct bottom sheets that don’t require internal navigation. Each bottom sheet corresponds to a specific route.

Key Concepts:

  • Transparent Modal (Again): Similar to Approach 1, a top-level screen is designated as a transparentModal to allow the bottom sheet to overlay the main content.
  • Slot Component: The Slot component from Expo Router is used within the bottom sheet’s layout. This acts as a placeholder for the content of each individual bottom sheet route.

Implementation Steps:

  1. Transparent Screen: Define a bottomSheet screen in your app/_layout.tsx with presentation: "transparentModal" and animation: "none".
    // app/_layout.tsx
    <Stack.Screen
        name="bottomSheet"
        options={{
            headerShown: false,
            animation: "none",
            presentation: "transparentModal",
        }}
    />
    
  2. Bottom Sheet Layout: Create the layout for your bottom sheets (app/bottomSheet/_layout.tsx). The crucial difference here is using the Slot component instead of a Stack. The backdrop for closing the sheet is also handled here.
     // app/bottomSheet/_layout.tsx
    const Approach2Layout = () => {
       const renderBackdrop = useCallback((props: BottomSheetBackdropProps) => {
           return <BottomSheetBackdrop {...props} disappearsOnIndex={-1} opacity={0.35} />;
       }, []);
    
        return (
            <BottomSheet backdropComponent={renderBackdrop} onClose={router.back}>
                <BottomSheetView style={styles.container}>
                    {/* Expo router's Slot inside BottomSheet */}
                    <Slot />
                </BottomSheetView>
            </BottomSheet>
        );
    };
    
  3. Route Files: Create individual route files (e.g., route1.tsx, route2.tsx) inside the bottomSheet directory. Each of these files will define the content of a separate, independent bottom sheet.

  4. Navigation: To display a specific bottom sheet, link to its route: <Link href="/bottomSheet/route1">.

Choosing the Right Approach

The best approach depends on your application’s needs:

  • Approach 1 (Single Bottom Sheet with Nested Routes): Use this when you have a group of related screens or a workflow that should be presented within a single bottom sheet context.
  • Approach 2 (Individual Route-Based Bottom Sheets): Opt for this when you have distinct bottom sheets that don’t require internal navigation, and each serves a specific, independent purpose.

Conclusion

By combining the power of Expo Router and gorhom/react-native-bottom-sheet, you can create a clean, maintainable, and user-friendly bottom sheet experience in your React Native applications. Route-based bottom sheets provide a structured approach to managing state and navigation, enhancing both the developer and user experience. While BottomSheetModal from the gorhom library remains a valid option for non-route-based scenarios or when you prefer manual state control, the methods presented here offer a more integrated solution within the Expo Router ecosystem.

Innovative Software Technology: Streamlining Your React Native Development

At Innovative Software Technology, we specialize in building high-quality, performant React Native applications. Our expertise in Expo Router and UI component libraries like gorhom/react-native-bottom-sheet allows us to create seamless and engaging user experiences. If you’re looking to implement dynamic bottom sheets, optimize navigation flows, or build a robust and scalable React Native app, we can help. Our team excels at crafting SEO-friendly mobile applications, ensuring your app is not only functional but also easily discoverable. We prioritize efficient code, user-centric design, and maintainable architectures to deliver solutions that meet your business goals and exceed user expectations. Let us help you leverage the latest technologies to build a top-tier mobile presence.

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed