Bottom Sheet
An interactive bottom sheet built on Expo UI with native snap points, gestures, and keyboard support.
Bottom Sheet is built on @expo/ui native bottom sheets — SwiftUI on iOS and Jetpack Compose on Android. Use it for draggable snap points, scrollable content, keyboard-aware forms, or simple modal sheets.

Installation
npx shadcn@latest add @tetra-ui/bottom-sheetUsage
import { Button, ButtonText } from "@/components/ui/button";
import {
BottomSheet,
BottomSheetBody,
BottomSheetClose,
BottomSheetContent,
BottomSheetFooter,
BottomSheetHeader,
BottomSheetTitle,
BottomSheetTrigger,
} from "@/components/ui/bottom-sheet";<BottomSheet>
<BottomSheetTrigger asChild>
<Button>
<ButtonText>Open</ButtonText>
</Button>
</BottomSheetTrigger>
<BottomSheetContent>
<BottomSheetHeader>
<BottomSheetTitle>Bottom Sheet Title</BottomSheetTitle>
</BottomSheetHeader>
<BottomSheetBody>
<Text className="text-foreground">Bottom Sheet Body</Text>
</BottomSheetBody>
<BottomSheetFooter>
<BottomSheetClose asChild>
<Button>
<ButtonText>Close</ButtonText>
</Button>
</BottomSheetClose>
</BottomSheetFooter>
</BottomSheetContent>
</BottomSheet>Snap points
Pass Expo UI SnapPoint values to BottomSheetContent:
"half"— medium detent (iOS) / partial expansion (Android)"full"— large detent (iOS) / full expansion (Android){ fraction: 0.4 }— fractional height{ height: 320 }— fixed height in points
<BottomSheetContent snapPoints={[{ fraction: 1 / 3 }, "half", "full"]}>
{/* ... */}
</BottomSheetContent>Omit snapPoints to auto-size the sheet to its content.
On iOS, multiple detents are supported natively. On Android, fractional and height snap points map to the nearest partial or expanded state.
Scrollable content
Use BottomSheetScrollView for long lists. Place BottomSheetHeader as a sibling above the scroll view:
<BottomSheetContent snapPoints={["half", "full"]}>
<BottomSheetHeader>
<BottomSheetTitle>List</BottomSheetTitle>
</BottomSheetHeader>
<BottomSheetScrollView>
{/* scrollable items */}
</BottomSheetScrollView>
</BottomSheetContent>Keyboard
The native sheet handles keyboard avoidance automatically. BottomSheetFooter stays above the keyboard without manual input hooks.
BottomSheetHeader, BottomSheetScrollView, and BottomSheetFooter must be direct children of BottomSheetContent (fragments are fine). On Android, children are split by component type so the footer can sit outside the scroll area in the Compose layout.
<BottomSheetContent snapPoints={["half", "full"]}>
<BottomSheetHeader>
<BottomSheetTitle>Send a message</BottomSheetTitle>
</BottomSheetHeader>
<BottomSheetScrollView>
<TextInput placeholder="Message" />
</BottomSheetScrollView>
<BottomSheetFooter>
<Button>Send</Button>
</BottomSheetFooter>
</BottomSheetContent>Changelog
2026-05-25 - Initial release
- Compound API:
BottomSheet,BottomSheetContent, and layout primitives - Snap points, pan-down-to-close, dynamic sizing
BottomSheetScrollView, stickyBottomSheetFooter
2026-06-22 - Keyboard Controller integration
- Added
react-native-keyboard-controlleras a dependency for footer keyboard avoidance on iOS.
2026-07-08 - Expo UI rewrite
- Rebuilt on @expo/ui native bottom sheets (SwiftUI on iOS, Jetpack Compose on Android)
- Removed
BottomSheetPortal,BottomSheetOverlay,useBottomSheet,useBottomSheetAnimation, anduseBottomSheetInputHandlers - Snap points now use Expo UI
SnapPointformat ("half","full",{ fraction },{ height }) - No portal or overlay required — the native sheet is the modal