Sheet
A bottom sheet that animates
Snap Points: [85,50,25]
Features
Lightweight implementation with dragging support.
Multiple snap points and a handle.
Automatically adjusts to screen size.
Accepts animations, themes, size props and more.
Installation
Sheet is already installed in tamagui, or you can install it independently:
yarn
npm
bun
pnpm
yarn add @tamagui/sheet
For native apps, we recommend setting up native portals to preserve React context inside Sheet content.
Anatomy
import { Sheet } from 'tamagui' // or '@tamagui/sheet'export default () => (<Sheet><Sheet.Overlay /><Sheet.Handle /><Sheet.Frame>{/* ...inner contents */}</Sheet.Frame></Sheet>)
API Reference
Sheet
Contains every component for the sheet.
Props
open
boolean
Set to use as controlled component.
defaultOpen
boolean
Uncontrolled open state on mount.
onOpenChange
(open: boolean) => void
Called on change open, controlled or uncontrolled.
position
number
Controlled position, set to an index of snapPoints.
defaultPosition
number
Uncontrolled default position on mount.
snapPoints
number[]
Default:
[80, 10]Array of numbers, 0-100 that corresponds to % of the screen it should take up. Should go from most visible to least visible in order. Use "open" prop for fully closed.
onPositionChange
(position: number) => void
Called on change position, controlled or uncontrolled.
dismissOnOverlayPress
boolean
Default:
trueControls tapping on the overlay to close, defaults to true.
animationConfig
Animated.SpringAnimationConfig
Default:
trueCustomize the spring used, passed to react-native Animated.spring().
native
boolean | "ios"[]
(iOS only) Render to a native sheet, must install native dependency first.
disableDrag
boolean
Disables all touch events to drag the sheet.
modal
boolean
Renders sheet into the root of your app instead of inline.
dismissOnSnapToBottom
boolean
Adds a snap point to the end of your snap points set to "0", that when snapped to will set open to false (uncontrolled) and call onOpenChange with false (controlled).
disableRemoveScroll
boolean
Default:
falseDisables the RemoveScroll behavior that prevents body scrolling while sheet is open. By default, RemoveScroll is enabled when the sheet is open and modal.
forceRemoveScrollEnabled
boolean
Default:
false@deprecated Use `disableRemoveScroll` instead. By default. Tamagui uses react-remove-scroll to prevent anything outside the sheet scrolling. This can cause some issues so you can override the behavior with this prop (either true or false).
portalProps
Object
YStack props that can be passed to the Portal that sheet uses when in modal mode.
moveOnKeyboardChange
boolean
Default:
falseNative-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible.
preferAdaptParentOpenState
boolean
Default:
falseBy default Sheet will prefer the open prop over a parent component that is controlling it via Adapt. In general if you want to Adapt to a sheet, you'd leave the open prop undefined. If you'd like to have the parent override the prop you've set manually on Sheet, set this to true.
Sheet.Overlay
Displays behind Frame. Extends YStack.
Sheet.Frame
Contains the content. Extends YStack.
Sheet.Handle
Shows a handle above the frame by default. On tap, it will cycle between
snapPoints, but this can be overridden with onPress.
Extends XStack.
Sheet.ScrollView
Allows scrolling within Sheet. Extends ScrollView.
Native Gesture Handler Integration
For the best gesture experience on iOS and Android, Sheet supports optional integration with react-native-gesture-handler. This provides:
- Smooth scroll-to-drag handoffs - Seamlessly transition between scrolling content and dragging the sheet
- No gesture conflicts - Sheet and ScrollView gestures coordinate properly
- Native-quality feel - Matches the behavior of system sheets
Setup
- Install
react-native-gesture-handler:
yarn
npm
bun
pnpm
yarn add react-native-gesture-handler
- Add the setup import to your app entry point (before any Tamagui imports):
// App.tsx or index.jsimport '@tamagui/native/setup-gesture-handler'import { GestureHandlerRootView } from 'react-native-gesture-handler'export default function App() {return (<GestureHandlerRootView style={{ flex: 1 }}>{/* Your app */}</GestureHandlerRootView>)}
That’s it! Sheet will automatically detect and use the native gesture handler when available.
Using Sheet.ScrollView
When using scrollable content inside a Sheet, use Sheet.ScrollView for proper gesture coordination:
<Sheet><Sheet.Handle /><Sheet.Frame><Sheet.ScrollView>{/* Scrollable content */}</Sheet.ScrollView></Sheet.Frame></Sheet>
This ensures:
- Scrolling up at the top of content works naturally
- Dragging down when scroll is at top drags the sheet
- Direction changes mid-gesture work smoothly
Without Gesture Handler
If you don’t set up react-native-gesture-handler, Sheet falls back to React Native’s built-in PanResponder. This works well for basic use cases but has some limitations on iOS where scroll and pan gestures can occasionally conflict.
Notes
For Android you need to manually re-propagate any context when using modal.
This is because React Native doesn’t support portals yet.
Native Support
We’ve deprecated the native prop in favor of using Adapt.