BottomSheet
A bottom sheet compatible with @gorhom/bottom-sheet.
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
A BottomSheet component with an API compatible with @gorhom/bottom-sheet. It wraps the platform-specific @expo/ui primitives: Jetpack Compose ModalBottomSheet on Android and SwiftUI BottomSheet on iOS. On web, it uses a vaul drawer.
If you need lower-level control over platform-specific styling, modifiers, or layout behavior, use the native primitives directly.
Installation
-Â npx expo install @expo/uiIf you are installing this in an existing React Native app, make sure to install expo in your project.
Migrating from @gorhom/bottom-sheet
-
Update imports from:
import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';To use
@expo/ui/community/bottom-sheet:import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; -
GestureHandlerRootViewfromreact-native-gesture-handleris not required by this implementation. You can leave it in place if other parts of your app need it. -
Component and hook exports such as
BottomSheetBackdrop,BottomSheetHandle,BottomSheetFooter,BottomSheetDraggableView,BottomSheetVirtualizedList,BottomSheetFlashList,useBottomSheetModal,useBottomSheetSpringConfigs, anduseBottomSheetTimingConfigsare not supported. Some related prop types are exported for API compatibility.
Basic usage
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetExample() { const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.snapToIndex(0)} /> <BottomSheet ref={sheetRef} snapPoints={['25%', '50%', '90%']} index={-1} onChange={index => { console.log('onChange', index); }} onClose={() => { console.log('closed'); }} enablePanDownToClose> <BottomSheetView style={{ flex: 1, padding: 24, alignItems: 'center' }}> <Text>Sheet content</Text> </BottomSheetView> </BottomSheet> </View> ); }
BottomSheetModal
Use BottomSheetModal when migrating from @gorhom/bottom-sheet modal APIs. It starts closed and opens with present().
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import { BottomSheetModal, BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function BottomSheetModalExample() { const modalRef = useRef<BottomSheetModal>(null); return ( <View style={{ flex: 1 }}> <Button title="Present" onPress={() => modalRef.current?.present()} /> <BottomSheetModal ref={modalRef} snapPoints={['50%', '90%']} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text>Modal content</Text> <Button title="Dismiss" onPress={() => modalRef.current?.dismiss()} /> </BottomSheetView> </BottomSheetModal> </View> ); }
Dynamic sizing
When snapPoints is not provided, the sheet sizes to fit its content by default. Use BottomSheetView for the sheet content wrapper.
import { useRef } from 'react'; import { Button, Text, View } from 'react-native'; import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet'; export default function DynamicBottomSheetExample() { const sheetRef = useRef<BottomSheet>(null); return ( <View style={{ flex: 1 }}> <Button title="Open" onPress={() => sheetRef.current?.present()} /> <BottomSheet ref={sheetRef} index={-1} enablePanDownToClose> <BottomSheetView style={{ padding: 24 }}> <Text>This sheet sizes itself to its content.</Text> </BottomSheetView> </BottomSheet> </View> ); }
Platform behavior
@gorhom/bottom-sheet renders inline at the bottom of its parent view. This component uses native modal presentation on Android and iOS, and a drawer overlay on web.
This difference is intentional. @gorhom/bottom-sheet owns the gesture and animation layer through react-native-gesture-handler and react-native-reanimated, while @expo/ui/community/bottom-sheet delegates those behaviors to Jetpack Compose, SwiftUI, and the web drawer primitive. As a result, this component is best suited for modal bottom sheet flows, including callsites that use the BottomSheet API rather than BottomSheetModal.
| Feature | Android | iOS | Web |
|---|---|---|---|
| Presentation | Jetpack Compose modal bottom sheet | SwiftUI sheet | vaul drawer |
| Snap points | Maps to partial and expanded states | Supports provided snap points | Supports provided snap points |
No snapPoints | Fits content | Fits content | Fits content |
| Pan down to close | Also enables back button and scrim tap dismiss | Also enables backdrop tap dismiss | Enables drawer dismiss |
| Persistent inline peek | Not supported | Not supported | Not supported |
Supported exports
| Export | Supported | Notes |
|---|---|---|
BottomSheet | Yes | Modal on Android and iOS, drawer on web |
BottomSheetModal | Yes | Starts closed and opens with present() |
BottomSheetModalProvider | Yes | Renders children directly for compatibility |
BottomSheetView | Yes | Wraps sheet content |
BottomSheetScrollView | Yes | Re-export of React Native ScrollView |
BottomSheetFlatList | Yes | Re-export of React Native FlatList |
BottomSheetSectionList | Yes | Re-export of React Native SectionList |
BottomSheetTextInput | Yes | Re-export of React Native TextInput |
useBottomSheet | Yes | Returns the sheet ref methods from context |
BottomSheetBackdrop | No | The native sheet or web drawer handles the backdrop |
BottomSheetHandle | No | The native sheet or web drawer handles the drag indicator |
BottomSheetFooter | No | No equivalent in this implementation |
Compatibility notes
snapPoints,index,onChange,onClose,onDismiss,enablePanDownToClose, andenableDynamicSizingare supported.handleComponent={null}hides the native or web drag indicator. Custom handle components are not rendered on native platforms.backgroundStyleapplies fully on web. On Android,backgroundColoris used for the native container color. On iOS, the system sheet background is used.- Animation, over-drag, content panning, handle panning, keyboard behavior, custom backdrop, custom background, custom footer, animated value, and detached props are accepted for API compatibility but do not change behavior.
API
import BottomSheet from '@expo/ui/community/bottom-sheet';
Components
Type: React.Element<BottomSheetProps>
Bottom sheet component. Defaults to index={0} and opens at the first snap point on mount.
Props for the BottomSheet component. API-compatible with @gorhom/bottom-sheet where native platform behavior allows.
boolean • Default: trueWhether the sheet should automatically size to fit its content.
boolean • Default: falseWhether the sheet can be dismissed by panning down.
number • Default: 0Initial snap point index. Set to -1 to start closed.
(index: number) => voidCalled when the current snap point index changes.
() => voidAlias for onClose for BottomSheetModal compatibility.
Type: React.Element<BottomSheetProps>
Modal variant of BottomSheet. Starts closed and opens with present().
Type: React.Element<{
children: React.ReactNode
}>
Provider for BottomSheetModal. It renders children directly for API compatibility.
Type: React.Element<BottomSheetViewProps>
A wrapper for content inside a BottomSheet.
boolean • Default: trueWhether the sheet should automatically size to fit its content.
boolean • Default: falseWhether the sheet can be dismissed by panning down.
number • Default: 0Initial snap point index. Set to -1 to start closed.
(index: number) => voidCalled when the current snap point index changes.
() => voidAlias for onClose for BottomSheetModal compatibility.
Hooks
Returns the imperative methods for the nearest BottomSheet.
BottomSheetMethodsTypes
Imperative methods exposed by BottomSheet and BottomSheetModal refs.
| Property | Type | Description |
|---|---|---|
| close | () => void | Close the bottom sheet. |
| collapse | () => void | Snap to the minimum snap point. |
| dismiss | () => void | Dismiss the bottom sheet. |
| expand | () => void | Snap to the maximum snap point. |
| forceClose | () => void | Force close the bottom sheet. |
| present | () => void | Present the bottom sheet at the first snap point. |
| snapToIndex | (index: number) => void | Snap to a snap point by index. |
| snapToPosition | (position: string | number) => void | Snap to a pixel value or percentage position. |