Sheet
You use the Sheet
component to avoid cluttering up the main content. With a bottom sheet, for example, the sheet starts off collapsed and the user expands it by dragging. In our example application, when the user opens an email we display the sender's information in a Sheet
.
import {Sheet} from 'navigation-react-native';
<Sheet hideable={true}>
<ScrollView />
</Sheet>
Note
On iOS, dragging the sheet isn't completely smooth. Removing the slight stutter will have to wait until React Native introduces synchronous view resizing.
The resting states of a Sheet
are called detents, for example, 'collapsed' or 'expanded'. By default the Sheet
is uncontrolled, where only the user can change the detent (by dragging). But it can also be controlled so you can programmatically change the detent. In our email example, when the user presses the sender's icon button we expand the Sheet
to reveal the sender's details.
const [detent, setDetent] = useState('hidden');
<Button onPress={() => setDetent('expanded')} />
<Sheet detent={detent} onChangeDetent={setDetent} hideable={true}>
<Button onPress={() => setDetent('hidden')} />
</Sheet>
There are props that allow you to configure the various detent heights. The peekHeight
prop sets the height of the 'collapsed' detent. The halfExpandedRatio
prop is for the 'halfExpanded' detent. And the height of the 'expanded' sheet is determined by the expandedHeight
or expandedOffset
props.
Interacting with the Presenting Scene
You can also have a non-modal Sheet
. The Sheet
is 100% native so, on Android, the non-modal version must be a child of a CoordinatorLayout
. In our email example, we make the sheet non-modal so the user can compose a reply while viewing the sender's details. We turn on nested scrolling so that the sheet's content scrolls seamlessly on Android when the user expands it.
<CoordinatorLayout>
<Sheet modal={false}>
<ScrollView nestedScrollEnabled={true} />
</Sheet>
</CoordinatorLayout>
Making a Full-Screen Sheet
You can make a full-screen Sheet
by setting bottom
to false. Because the Sheet
is 100% native, a full-screen sheet can't be dismissed by dragging on iOS. Instead, you have to programatically close it by setting the detent to 'hidden'. In our email example, we add a 'Create Contact' button to the contacts list. When pressed, we display a sheet to collect the contact's name and number.
<Sheet bottom={false} detent={detent} onChangeDetent={setDetent}>
<Contact />
</Sheet>
Navigating in a Sheet
A sheet can have its own stack of scenes independent of the main stack. Inside the Sheet
, you render a NavigationStack
with its own StateNavigator
. We need two scenes in the full-screen sheet in our email example. The first collects the new contact's name and number and the second collects their address. We create a StateNavigator
with a State
for each scene.
const contactNavigator = new StateNavigator([
{key: 'contact'},
{key: 'address', trackCrumbTrail: true}
]);
Then we render the NavigationStack
inside the Sheet
and assign it the StateNavigator
we just created.
<Sheet>
<NavigationHandler stateNavigator={contactNavigator}>
<NavigationStack>
<Scene stateKey="contact"><Contact /></Scene>
<Scene stateKey="address"><Address /></Scene>
</NavigationStack>
</NavigationHandler>
</Sheet>