Skip to main content

Tutorial

🚀 Step-by-Step Guide to implement BottomSheet in React Native with Expo and React Navigation.

Video Tutorial​

Watch our detailed video guide for a hands-on implementation walkthrough:

Prerequisites​

Before you begin, make sure you have:

  • React Native project set up with Expo
  • React Navigation installed
  • Basic understanding of React Native and TypeScript

Installation​

Peer Dependencies

Make sure you have these peer dependencies installed in your React Native or Expo project. Using incompatible versions may cause unexpected behavior or crashes:

{
"react": "^18.3.1",
"react-native": "^0.76.7",
"react-native-reanimated": "^3.16.7",
"react-native-gesture-handler": "^2.20.2",
"react-native-safe-area-context": "^4.12.0",
"@react-navigation/native": "^6.x"
}
  1. Install the package using your preferred package manager:
npm install @masumdev/rn-bottom-sheet
# or
yarn add @masumdev/rn-bottom-sheet
# or
bun add @masumdev/rn-bottom-sheet
  1. Install required peer dependencies:
npm install react-native-reanimated react-native-gesture-handler react-native-safe-area-context @react-navigation/native

Expo Configuration​

Expo Installation

If you're using Expo, use expo install to ensure compatibility with your Expo SDK version.

  1. Install dependencies in Expo:
npx expo install react-native-reanimated react-native-gesture-handler react-native-safe-area-context @react-navigation/native
  1. Update your babel.config.js:
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'],
};
};
  1. Add to your app.json or app.config.js:
{
"expo": {
"plugins": [
"react-native-reanimated"
]
}
}
Performance Optimization

Enable Hermes engine in your React Native project for better performance with animations and gestures.

Basic Implementation​

Provider Placement

Always place the BottomSheetProvider at the root level of your app, preferably after other providers like NavigationContainer. Incorrect provider placement can cause the bottom sheet to malfunction.

Simple Content​

  1. First, wrap your app with the BottomSheetProvider:
import { BottomSheetProvider } from '@masumdev/rn-bottom-sheet';

export default function App() {
return (
<BottomSheetProvider>
{/* Your app content */}
</BottomSheetProvider>
);
}
  1. Use the useBottomSheet hook in your components:
import { useBottomSheet } from '@masumdev/rn-bottom-sheet';

export default function MyComponent() {
const { expand, close, setContent, setSheetTitle } = useBottomSheet();

const handleOpenSheet = () => {
setSheetTitle('My Bottom Sheet');
setContent(
<View style={{ padding: 16 }}>
<Text>Your bottom sheet content here</Text>
</View>
);
expand('50%'); // Opens to 50% of screen height
};

return (
<Button title="Open Bottom Sheet" onPress={handleOpenSheet} />
);
}

Scrollable Content​

Untuk konten yang panjang, gunakan varian ScrollView:

import { useBottomSheet } from '@masumdev/rn-bottom-sheet';

export default function ScrollableContent() {
const { expand, setContent, setSheetTitle, setVariant } = useBottomSheet();

const handleOpenSheet = () => {
setSheetTitle('Scrollable Content');
setVariant('scroll');
setContent(
<View style={{ padding: 16 }}>
{/* Konten panjang di sini */}
{Array(20).fill(0).map((_, i) => (
<Text key={i} style={{ marginBottom: 16 }}>
Item {i + 1}
</Text>
))}
</View>
);
expand('70%');
};

return (
<Button title="Open Scrollable Sheet" onPress={handleOpenSheet} />
);
}

List Content​

Untuk menampilkan daftar item, gunakan varian FlatList:

import { useBottomSheet } from '@masumdev/rn-bottom-sheet';

export default function ListContent() {
const { expand, setSheetTitle, setVariant, setListData, setRenderItem } = useBottomSheet();

const data = Array(50).fill(0).map((_, i) => ({
id: i + 1,
title: `Item ${i + 1}`
}));

const handleOpenSheet = () => {
setSheetTitle('List Content');
setVariant('flatlist');
setListData(data);
setRenderItem(({ item }) => (
<Pressable
onPress={() => console.log(item)}
style={{ padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' }}
>
<Text>{item.title}</Text>
</Pressable>
));
expand('70%');
};

return (
<Button title="Open List Sheet" onPress={handleOpenSheet} />
);
}

Customization Options​

Responsive Design

Choose snap points based on your content height and screen size. For forms and detailed content, use higher snap points (60-100%), while for action sheets and simple lists, use lower snap points (30-50%).

Snap Points​

You can customize the height of the bottom sheet using snap points:

// Available snap points: 10% to 90%
expand('70%'); // Opens to 70% of screen height

Styling​

Customize the appearance using provider props:

<BottomSheetProvider
backgroundColor="#ffffff"
backDropColor="rgba(0,0,0,0.5)"
defaultSnapTo="50%"
maxSnapTo="90%"
onStateChange={(isOpen) => console.log('Sheet state:', isOpen)}
>
{/* Your app content */}
</BottomSheetProvider>

Advanced Features​

Gesture Handling​

Bottom sheet mendukung gesture untuk membuka dan menutup:

Best Practices​

Memory Management

Avoid setting complex state or running expensive operations during sheet animations. This can cause performance issues and jerky animations.

  1. State Management

    • Use the onStateChange callback to handle sheet state changes
    • Keep content updates synchronized with sheet state
  2. Performance

    • Memoize content when possible
    • Avoid heavy computations during animations
  3. User Experience

    • Provide clear visual feedback
    • Handle back button/gesture appropriately
    • Use appropriate snap points for content size

Advanced Features​

Gesture Handling​

tip

Implement gesture handlers using the react-native-gesture-handler library for smooth interactions. Consider debouncing gesture callbacks for better performance.

import { useBottomSheet } from '@masumdev/rn-bottom-sheet';

const { setContent, expand } = useBottomSheet();

const CustomContent = () => {
const handleSwipeComplete = (direction) => {
if (direction === 'up') {
expand('90%');
} else if (direction === 'down') {
expand('30%');
}
};

return (
<GestureHandlerRootView>
<PanGestureHandler onGestureEvent={handleSwipeComplete}>
<View style={styles.container}>
<Text>Swipe up or down</Text>
</View>
</PanGestureHandler>
</GestureHandlerRootView>
);
};

Custom Animations​

tip

Use Reanimated's native driver animations for optimal performance. Worklets run on the UI thread and provide smooth animations.

import { useBottomSheet } from '@masumdev/rn-bottom-sheet';
import Animated, { withSpring } from 'react-native-reanimated';

const AnimatedContent = () => {
const scale = useSharedValue(1);

const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: withSpring(scale.value) }],
}));

return (
<Animated.View style={[styles.container, animatedStyle]}>
<Text>Animated Content</Text>
</Animated.View>
);
};

Common Use Cases​

const handleOpenForm = () => {
setSheetTitle('New Item');
setContent(
<View style={{ padding: 16 }}>
<TextInput placeholder="Enter item name" />
<Button title="Submit" onPress={handleSubmit} />
</View>
);
expand('60%');
};

Action Sheets​

const handleOpenActions = () => {
setSheetTitle('Choose Action');
setContent(
<View style={{ padding: 16 }}>
<Pressable onPress={() => { /* action 1 */ }}>
<Text>Action 1</Text>
</Pressable>
<Pressable onPress={() => { /* action 2 */ }}>
<Text>Action 2</Text>
</Pressable>
</View>
);
expand('30%');
};

Troubleshooting​

Debugging

Enable the React Native Debugger and monitor the component lifecycle to identify issues. Check the console for any warnings or errors related to gesture handling or animations.

Common Issues​

  1. Sheet not appearing

    • Ensure BottomSheetProvider is at the root level
    • Check if content is being set correctly
    • Verify all peer dependencies are properly installed
  2. Gesture handling issues

    • Make sure react-native-gesture-handler is properly configured
    • Check if GestureHandlerRootView wraps your app
  3. Animation performance

    • Enable the native driver for animations
    • Use Hermes engine for better performance
    • Avoid heavy computations during animations
  4. Gesture issues

    • Verify react-native-reanimated is properly installed
    • Check for conflicting gesture handlers
  5. Layout problems

    • Ensure proper usage of SafeAreaView
    • Check for conflicting style properties

For more examples and advanced usage, check out our demo page.