Skip to main content

For @gorhom/bottom-sheet

Bottom sheets you can await.

sheet-scope manages gorhom's bottom-sheet modals in React Native. You open a sheet with one typed call and get its result back as a promise. The sheet is mounted only while it's open, and it closes when the screen that owns it unmounts.

  • JavaScript only
  • About 7.5 KB minified
  • Built on @gorhom/bottom-sheet v5
Cart
Item
Wireless headphonesIn your cart

Open the sheet, then pop the screen: the sheet closes with it. This phone imitates the behaviour in the browser. It isn't the library running.

const confirmed = await sheets.show('confirm', {
  title: 'Delete this item?',
});
  1. Tap Delete item on the phone to see what the promise resolves with.

sheets mounted: 0

Why it exists

gorhom draws the sheet. Something still has to manage it.

@gorhom/bottom-sheet handles the hard part: gestures, animation and the keyboard. It leaves the bookkeeping to you: where each sheet is rendered, how a screen opens it, how the answer gets back, and what happens to the sheet when its screen goes away. sheet-scope is that bookkeeping.

Scoped

A sheet closes with the screen that owns it

A global sheet manager lets you open a sheet from anywhere, but then the sheet belongs to the whole app. If the screen that opened it goes away, the sheet stays up over whatever comes next.

Here, every sheet belongs to a <SheetScope>. When the scope unmounts, for example because its screen was popped, its sheets close.

Lazily mounted

A sheet costs nothing until it opens

The usual pattern adds a <BottomSheetModal> and a ref to the screen for every sheet it might show, and loads each sheet's code along with the screen.

Here, a sheet isn't rendered, and its module isn't evaluated, until you call show() or preload(). Once it has closed, it unmounts.

Typed

Names, props and results are checked

Sheet names passed as strings, loosely typed props, and results handed back through callbacks are all easy to get wrong.

Here, all three are inferred from your sheet components. show('confirm', { title }) checks title at compile time and resolves with the sheet's result.

Before and after

The same delete confirmation, both ways

With gorhom alone
function ItemScreen() {
const confirmRef = useRef<BottomSheetModal>(null);

const onDone = (confirmed: boolean) => {
confirmRef.current?.dismiss();
if (confirmed) deleteItem();
};

return (
<>
<Button
title="Delete"
onPress={() => confirmRef.current?.present()}
/>
{/* One of these, and a ref, per sheet */}
<BottomSheetModal ref={confirmRef}>
<ConfirmContent
title="Delete this item?"
onDone={onDone}
/>
</BottomSheetModal>
</>
);
}
With sheet-scope
function ItemScreen() {
const sheets = useSheets();

const onDelete = async () => {
const confirmed = await sheets.show('confirm', {
title: 'Delete this item?',
});
if (confirmed) deleteItem();
};

return <Button title="Delete" onPress={onDelete} />;
}

The sheet itself is still a gorhom sheet. Its root element, <SheetModal>, takes BottomSheetModal's props, apart from two the library controls, so snap points, backdrops and gestures work the way you already know.