Getting started
Install
The library needs React 18 or newer and @gorhom/bottom-sheet v5, which in turn needs Reanimated and Gesture Handler.
With Expo:
npx expo install @jdarshan5/sheet-scope @gorhom/bottom-sheet \
react-native-reanimated react-native-gesture-handler
With bare React Native:
yarn add @jdarshan5/sheet-scope @gorhom/bottom-sheet \
react-native-reanimated react-native-gesture-handler
cd ios && pod install
Reanimated 4 also needs react-native-worklets, so add it to the command if that's the version you get.
Then finish Reanimated's and Gesture Handler's setup (Babel plugin, root view) by following gorhom's installation guide and Reanimated's.
1. Write a sheet
A sheet is a component whose root is <SheetModal>. SheetModal takes any BottomSheetModal prop, such as snap points or a backdrop, except the two the library controls.
The sheet also receives a sheet prop. Its type, SheetHandle<R>, declares what the sheet resolves with.
import { BottomSheetView } from '@gorhom/bottom-sheet';
import { SheetModal, type SheetHandle } from '@jdarshan5/sheet-scope';
import { Button, Text } from 'react-native';
type Props = { title: string; sheet: SheetHandle<boolean> };
export default function ConfirmSheet({ title, sheet }: Props) {
return (
<SheetModal>
<BottomSheetView>
<Text>{title}</Text>
<Button title="Cancel" onPress={() => sheet.close(false)} />
<Button title="Delete" onPress={() => sheet.close(true)} />
</BottomSheetView>
</SheetModal>
);
}
2. Register your sheets
Each entry is a dynamic import, so a sheet's code isn't evaluated until it's first opened or preloaded. Each module must export the sheet component as its default export. This file is also where the types come from.
import { createSheetScope, defineSheets } from '@jdarshan5/sheet-scope';
export const { SheetScope, useSheets } = createSheetScope(
defineSheets({
confirm: () => import('./ConfirmSheet'),
// `unique: false` lets several copies of a sheet be open at once.
picker: { load: () => import('./PickerSheet'), unique: false },
})
);
3. Add the providers
GestureHandlerRootView and gorhom's BottomSheetModalProvider go above your root <SheetScope>:
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SheetScope } from './sheets';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<BottomSheetModalProvider>
<SheetScope>{/* your navigator and screens */}</SheetScope>
</BottomSheetModalProvider>
</GestureHandlerRootView>
);
}
4. Open sheets
const sheets = useSheets();
const deleteItem = async () => {
const confirmed = await sheets.show('confirm', { title: 'Delete this item?' });
// confirmed: boolean | undefined
if (confirmed) {
// ...
}
};
show() resolves once the sheet has finished animating closed. It resolves with the value passed to sheet.close(value), or undefined if the sheet closed without one: a swipe-down, a tap on its backdrop, Android's back button, hide(), or its scope unmounting.
- iOS
- Android
It only rejects on real errors, such as a failed import or a sheet that throws while rendering. See When a sheet fails.
Next
- Scopes: decide which sheets close with which screen.
- API: everything
useSheets()and<SheetScope>offer. - Good to know: things worth knowing before you ship.