A customizable step-by-step bottom sheet component for React Native with smooth animations, perfect for onboarding flows, wizards, and multi-step forms.
- 🎯 Step-by-step navigation with smooth animations
- 🎨 Fully customizable styling and behavior
- 📱 Built on @gorhom/bottom-sheet for reliable performance
- ⚡ Dynamic height adjustment based on content
- 🎭 Animated transitions between steps
- 🎮 Gesture support with pan-to-close functionality
- 🔧 TypeScript support with full type definitions
- 🎪 Flexible step components - use any React component as a step
npm install react-native-step-bottom-sheet
# or
yarn add react-native-step-bottom-sheet
Make sure you have these peer dependencies installed:
npm install @gorhom/bottom-sheet react-native-gesture-handler react-native-reanimated react-native-safe-area-context
# or
yarn add @gorhom/bottom-sheet react-native-gesture-handler react-native-reanimated react-native-safe-area-context
Important: Before using the component, you need to set up the required providers in your app's root layout.
Add the providers to your app/_layout.tsx
:
import { Slot } from "expo-router";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
export default function Layout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<BottomSheetModalProvider>
<Slot />
</BottomSheetModalProvider>
</GestureHandlerRootView>
);
}
Add the providers to your App.tsx
or root component:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import YourNavigator from './YourNavigator';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<NavigationContainer>
<BottomSheetModalProvider>
<YourNavigator />
</BottomSheetModalProvider>
</NavigationContainer>
</GestureHandlerRootView>
);
}
import React, { useRef, useCallback } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import BottomSheet from '@gorhom/bottom-sheet';
import { StepBottomSheet } from 'react-native-step-bottom-sheet';
// Define your step components
const WelcomeStep = () => (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>Welcome! 🎉</Text>
<Text>Get started with our amazing app</Text>
</View>
);
const SetupStep = () => (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>Setup 🔧</Text>
<Text>Let's configure your preferences</Text>
</View>
);
const ReadyStep = () => (
<View style={{ padding: 20 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>Ready! 🚀</Text>
<Text>You're all set to begin</Text>
</View>
);
const App = () => {
const bottomSheetRef = useRef<BottomSheet>(null);
const steps = [WelcomeStep, SetupStep, ReadyStep];
const handleOpenPress = useCallback(() => {
bottomSheetRef.current?.snapToIndex(0);
}, []);
const handleClosePress = useCallback(() => {
bottomSheetRef.current?.close();
}, []);
return (
<GestureHandlerRootView style={{ flex: 1, backgroundColor: "gray" }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity onPress={handleOpenPress}>
<Text>Open</Text>
</TouchableOpacity>
</View>
<StepBottomSheet
ref={bottomSheetRef}
steps={steps}
onClose={handleClosePress}
/>
</GestureHandlerRootView>
);
};
import React from 'react';
import { View, Button } from 'react-native';
import { StepBottomSheet, useStepBottomSheet } from 'react-native-step-bottom-sheet';
const App = () => {
const { ref, open, close, currentStep } = useStepBottomSheet();
const handleStepChange = (stepIndex: number) => {
console.log('Current step:', stepIndex);
};
return (
<View style={{ flex: 1 }}>
<Button title="Open Custom Steps" onPress={open} />
<StepBottomSheet
ref={ref}
steps={[WelcomeStep, SetupStep, ReadyStep]}
onClose={close}
onStepChange={handleStepChange}
stepContentProps={{
initialStep: 0,
showNavigation: true,
showIndicators: true,
navigationLabels: {
previous: 'Back',
next: 'Continue'
},
styles: {
container: {
backgroundColor: '#f8f9fa',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
},
navigationButton: {
backgroundColor: '#007AFF',
borderRadius: 12,
},
stepIndicatorActive: {
backgroundColor: '#007AFF',
}
}
}}
snapPoints={['90%']}
enablePanDownToClose={true}
backdropProps={{
opacity: 0.5,
}}
/>
</View>
);
};
Prop | Type | Default | Description |
---|---|---|---|
steps |
React.ComponentType[] |
Required | Array of React components to render as steps |
onClose |
() => void |
undefined |
Callback when bottom sheet is closed |
onStepChange |
(stepIndex: number) => void |
undefined |
Callback when step changes |
stepContentProps |
Partial<StepContentProps> |
{} |
Props to pass to the StepContent component |
snapPoints |
string[] |
["100%"] |
Bottom sheet snap points |
enablePanDownToClose |
boolean |
true |
Enable pan down to close gesture |
enableDynamicSizing |
boolean |
true |
Enable dynamic sizing based on content |
backdropProps |
object |
{} |
Props for the backdrop component |
Prop | Type | Default | Description |
---|---|---|---|
steps |
React.ComponentType[] |
Required | Array of step components |
onClose |
() => void |
undefined |
Close callback |
onStepChange |
(stepIndex: number) => void |
undefined |
Step change callback |
initialStep |
number |
0 |
Initial step index |
showNavigation |
boolean |
true |
Show navigation buttons |
showIndicators |
boolean |
true |
Show step indicators |
navigationLabels |
{previous: string, next: string} |
{previous: 'Previous', next: 'Next'} |
Navigation button labels |
styles |
object |
{} |
Custom styles object |
Returns an object with:
Property | Type | Description |
---|---|---|
ref |
RefObject |
Ref to pass to StepBottomSheet |
open |
() => void |
Function to open the bottom sheet |
close |
() => void |
Function to close the bottom sheet |
goToStep |
(stepIndex: number) => void |
Function to navigate to specific step |
currentStep |
number |
Current step index |
isOpen |
boolean |
Whether the bottom sheet is open |
The component supports extensive styling customization through the styles
prop in stepContentProps
:
const customStyles = {
container: {
backgroundColor: '#ffffff',
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
},
navigationButton: {
backgroundColor: '#007AFF',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
navigationButtonDisabled: {
backgroundColor: '#E5E5E5',
},
navigationButtonText: {
color: 'white',
fontSize: 16,
fontWeight: '600',
},
navigationButtonTextDisabled: {
color: '#999',
},
stepIndicator: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: '#E5E5E5',
},
stepIndicatorActive: {
backgroundColor: '#007AFF',
},
};
Check out the /example
folder for complete working examples including:
- Basic step navigation
- Custom styling
- Dynamic content
- Integration with forms
- Onboarding flows
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
MIT License - see LICENSE file for details.
Built on top of the excellent @gorhom/bottom-sheet library.