Skip to main content
Version: Unreleased

Adding Footer

Do you need action buttons on the sheet? Or perhaps a small banner at the bottom? We've got you covered!

TrueSheet provides first-class support for a Footer component. The footer is pinned to the bottom of the sheet, takes up space below the content, and its height is included in the auto detent calculation.

How?

Define your footer component.

const SomeFooter = () => {
return (
<View>
<Text>My Foot-er is Awesome.</Text>
</View>
)
}

Stick it in the footer.

const App = () => {
return (
<TrueSheet footer={SomeFooter}>
<View />
</TrueSheet>
)
}
tip

For best performance, use ReactElement instead!

const App = () => {
return (
<TrueSheet
ref={sheet}
footer={
<View>
<Text>My Foot-er is more awesome.</Text>
</View>
}
>
<View />
</TrueSheet>
)
}

Safe Area Handling

The footer owns the sheet's bottom edge, so it automatically absorbs the bottom safe-area inset as padding when insetAdjustment is "automatic" (the default). Your footer content stays above the home indicator while its background fills the inset — no manual padding needed.

const MyFooter = () => {
return (
<View style={{ height: 60, justifyContent: 'center', alignItems: 'center' }}>
<Text>Footer Content</Text>
</View>
);
};

// Usage
<TrueSheet detents={['auto']} footer={<MyFooter />} footerStyle={{ backgroundColor: '#333' }}>
{/* content */}
</TrueSheet>

The inset is applied to the footer component itself, so set your background via footerStyle (or on your footer's root view) for it to fill the safe area.

When the keyboard opens, an absolute footer rises above it and the inset is skipped automatically — no gap above the keyboard. A relative footer stays in the layout flow and keeps its inset. See Keyboard Handling.

note

On iPad, the sheet is displayed as a floating modal, so no inset is applied. Set insetAdjustment="never" to opt out entirely.

By default, the footer takes up space below the content and its height is included in the auto detent calculation. Set footerOptions.position to 'absolute' to float the footer over the content instead — it stays pinned to the bottom edge but no longer adds to the auto detent height. An absolute footer absorbs the bottom safe-area inset the same way a relative one does — see Safe Area Handling.

const App = () => {
return (
<TrueSheet
detents={['auto']}
footerOptions={{ position: 'absolute' }}
footer={<Fab />}
>
<FlatList
data={items}
contentContainerStyle={{ paddingBottom: FOOTER_HEIGHT }}
renderItem={({ item }) => <ItemRow item={item} />}
/>
</TrueSheet>
)
}
tip

Since the footer overlaps the content, add bottom padding to your content (e.g. contentContainerStyle) so it ends above the footer.

info

A relative footer is laid out below the content — if your content is taller than the sheet's visible height (e.g. fixed detents), bound it with flex: 1 so the footer stays visible. Use 'absolute' if you want the footer to float regardless of the content's height.

An absolute footer's height counts toward the "peek" detent — collapse the sheet down to just the header, footer, and any peeking content.

const App = () => {
return (
<TrueSheet
detents={['peek', 0.9]}
initialDetentIndex={0}
footer={<SheetActions />}
footerOptions={{ position: 'absolute' }}
>
<BookingDetails />
</TrueSheet>
)
}

Since an absolute footer floats over the content, it stays visible at every detent. A relative footer is laid out below the content, so it's pushed off-screen at the peek detent and is excluded from the peek height. See Peeking Content for the full guide.