# Installation (/install) ## Prerequisites [#prerequisites] * React Native >= 0.80 * New Architecture enabled (default in RN 0.76+) * Xcode 26.1+ (liquid glass support) ### Compatibility [#compatibility] | TrueSheet | React Native | Expo SDK | | --------- | ------------ | -------- | | 3.7+ | 0.81-0.86 | 54-57 | | 3.6 | 0.80 | 52-53 | This package is not compatible with [Expo Go](https://docs.expo.dev/get-started/expo-go/). Use this with [Expo CNG](https://docs.expo.dev/workflow/continuous-native-generation/) instead. ## Expo [#expo] ```sh npx expo install @lodev09/react-native-true-sheet ``` See [EAS Build troubleshooting](troubleshooting#eas-build-configuration) for build configuration. ## Bare React Native [#bare-react-native] npm pnpm yarn bun ```bash npm install @lodev09/react-native-true-sheet ``` ```bash pnpm add @lodev09/react-native-true-sheet ``` ```bash yarn add @lodev09/react-native-true-sheet ``` ```bash bun add @lodev09/react-native-true-sheet ``` Then install the native dependencies: ```sh cd ios && pod install ``` # Introduction (/intro) The ***true*** native bottom sheet experience for your [React Native](https://reactnative.dev) Apps.
preview ios preview android preview web
## Features [#features] * ⚡ **Powered by Fabric** - Built on React Native's new architecture for maximum performance * 🚀 **Fully Native** - Implemented in the native realm, zero JS hacks * ♿ **Accessible** - Native accessibility and screen reader support out of the box * 🔄 **Flexible API** - Use [imperative methods](reference/methods#ref-methods) or [lifecycle events](reference/events) * ⌨️ **Keyboard Handling** - Built-in [keyboard handling](guides/keyboard) with automatic adjustment * 🪟 **Liquid Glass** - [iOS 26+ Liquid Glass](guides/liquid-glass) support out of the box, featured in [Expo Blog](https://expo.dev/blog/how-to-create-apple-maps-style-liquid-glass-sheets) * 🐎 **Reanimated** - First-class support for [react-native-reanimated](guides/reanimated) * 🧭 **React Navigation** - Built-in [sheet navigator](guides/navigation) for seamless navigation integration * 🌐 **Web Support** - Full [web support](guides/web) out of the box # Migrating to v3 (/migration) This guide will help you migrate from TrueSheet v2 to v3. Version 3 brings full Fabric (New Architecture) support and several improvements. ## Breaking Changes [#breaking-changes] ### 1. Fabric Architecture Required [#1-fabric-architecture-required] Version 3 is built exclusively for React Native's **New Architecture (Fabric)**. The old Paper architecture is no longer supported. **Requirements:** * React Native >= 0.76 (Expo SDK 52+) * New Architecture enabled (default in RN 0.76+) If you're on React Native 0.76+, the New Architecture is enabled by default. No additional configuration is needed. ### 2. Prop Renames [#2-prop-renames] Several props have been renamed for better clarity: | v2 Prop | v3 Prop | | ----------------------- | ------------------------------ | | `sizes` | `detents` | | `initialIndex` | `initialDetentIndex` | | `initialIndexAnimated` | `initialDetentAnimated` | | `contentContainerStyle` | *(removed - no longer needed)* | | `FooterComponent` | `footer` | | `edgeToEdge` | *(removed)* | | `onPresent` | `onDidPresent` | | `onDismiss` | `onDidDismiss` | | `onSizeChange` | `onDetentChange` | | `dimmedIndex` | `dimmedDetentIndex` | **Migration:** ```tsx // ❌ v2 } edgeToEdge onPresent={(e) => console.log(e.nativeEvent)} onDismiss={() => console.log('dismissed')} onSizeChange={(e) => console.log(e.nativeEvent)} /> // ✅ v3 } onDidPresent={(e) => console.log(e.nativeEvent)} onDidDismiss={() => console.log('dismissed')} onDetentChange={(e) => console.log(e.nativeEvent)} /> ``` ### 3. Removed Props [#3-removed-props] The following props have been removed in v3: #### `grabberProps` (Android) [#grabberprops-android] The `grabberProps` prop has been removed. The grabber is now rendered **natively** on both iOS and Android following Material Design 3 specifications. Use the `grabber` boolean prop to show or hide the native grabber. **Migration:** ```tsx // ❌ v2 {/* ... */} // ✅ v3 - grabber is native, use boolean to show/hide {/* ... */} ``` #### `scrollRef` (iOS) [#scrollref-ios] The `scrollRef` prop has been removed. Scroll views are now **automatically detected** on iOS. Use the new `scrollable` prop to enable automatic ScrollView pinning. **Migration:** ```tsx // ❌ v2 const scrollViewRef = useRef(null) {/* ... */} // ✅ v3 {/* ... */} ``` See the [Scrolling guide](guides/scrolling) for more information about `scrollable`. #### `contentContainerStyle` [#contentcontainerstyle] The `contentContainerStyle` prop has been removed as it's no longer needed with the new architecture. Style your content directly instead. ### 4. Detent Value Changes [#4-detent-value-changes] Detent values now use **fractional values (0-1)** instead of percentage strings. **Migration:** ```tsx // ❌ v2 // ✅ v3 ``` The `"auto"` detent still works the same way! ### 5. Native Bottom Safe Area Handling [#5-native-bottom-safe-area-handling] Both iOS and Android now handle bottom safe area insets natively for the sheet. This means the sheet height includes the safe area automatically, providing consistent behavior across all devices. **What this means:** * The `position`, `index`, and `detent` values are calculated purely from the actual sheet position relative to screen height * A sheet at detent `0.5` will be taller than `0.5 * screenHeight` because the system adds the bottom safe area internally **Footer with auto detent:** The footer is pinned to the bottom edge of the sheet. When using an `auto` detent, the sheet height includes the safe area, so your footer needs to extend into it: ```tsx import { Platform } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; const isIPad = Platform.OS === 'ios' && Platform.isPad; const MyFooter = () => { const insets = useSafeAreaInsets(); const bottomInset = isIPad ? 0 : insets.bottom; return ( Footer Content ); }; // Usage }> {/* content */} ``` This ensures the footer background extends into the safe area while keeping the content above the home indicator. On iPad, the sheet is displayed as a floating modal, so bottom padding is not needed. See the [Footer guide](guides/footer) for more details. ### 6. Background and Blur Behavior Changes [#6-background-and-blur-behavior-changes] #### `backgroundColor` Default Value [#backgroundcolor-default-value] The `backgroundColor` prop no longer defaults to `"white"`. It now uses the **system default** when not provided, which matches the platform's native sheet background. **Migration:** ```tsx // ❌ v2 - backgroundColor defaults to white // ✅ v3 - backgroundColor uses system default (transparent on iOS) // If you want white background, explicitly set it: ``` #### `backgroundBlur` No Longer Overrides `backgroundColor` [#backgroundblur-no-longer-overrides-backgroundcolor] In v2, setting `backgroundBlur` (previously `blurTint`) would completely override the `backgroundColor`. In v3, `backgroundBlur` now **applies a blur effect over** the `backgroundColor`, allowing you to combine both for richer visual effects. **Migration:** ```tsx // ❌ v2 - backgroundBlur overrides backgroundColor (backgroundColor is ignored) // ✅ v3 - backgroundBlur applies over backgroundColor (red + light blur) // If you want only blur without background color: ``` ## New Features in v3 [#new-features-in-v3] ### 1. Automatic Edge-to-Edge Detection (Android) [#1-automatic-edge-to-edge-detection-android] TrueSheet now automatically detects and adapts to Android's edge-to-edge display mode. The sheet respects the status bar when fully expanded. This feature is **Android-only** and requires React Native 0.81+ with `edgeToEdgeEnabled=true` in your `android/gradle.properties`. See the [Edge-to-Edge guide](guides/edge-to-edge) for details. ### 2. Enhanced Event System [#2-enhanced-event-system] Version 3 introduces new lifecycle and interaction events for better control: #### New Events: [#new-events] * **`onMount`** - Called when the sheet's content is mounted and ready * **`onWillPresent`** - Called when the sheet is about to be presented * **`onDidPresent`** - Called when the sheet has been presented * **`onWillDismiss`** - Called when the sheet is about to be dismissed * **`onDidDismiss`** - Called when the sheet has been dismissed * **`onDragBegin`** - Called when the sheet begins dragging * **`onDragChange`** - Called continuously while the sheet is being dragged * **`onDragEnd`** - Called when sheet dragging has ended * **`onPositionChange`** - Called continuously when the sheet's position changes * **`onWillFocus`** - Called when the sheet is about to regain focus after a sheet on top begins dismissing * **`onDidFocus`** - Called when the sheet has regained focus after a sheet on top is dismissed * **`onWillBlur`** - Called when the sheet is about to lose focus because another sheet is about to be presented on top * **`onDidBlur`** - Called when the sheet has lost focus because another sheet is presented on top These events provide more granular control over the sheet's lifecycle and user interactions. See the [Lifecycle Events documentation](reference/events) for detailed usage and examples. ### 3. iPad Support with Presentation [#3-ipad-support-with-presentation] Version 3 now includes first-class iPad support with the new `presentation` prop. `'page'` (default) uses a large page sheet for better readability on iPad. `'form'` uses a centered floating form sheet. ```tsx ``` This feature is **iOS 17+ only** and defaults to `'page'`. Set to `'form'` to use a centered form sheet presentation on iPad. ### 4. Improved Performance [#4-improved-performance] * Faster rendering with Fabric architecture * Built-in lazy loading by default * Smoother animations and transitions ### 5. First-Class Reanimated v4 Support [#5-first-class-reanimated-v4-support] Version 3 introduces dedicated components for seamless integration with `react-native-reanimated` v4: #### New Components: [#new-components] * **`ReanimatedTrueSheetProvider`** - Context provider for managing shared values * **`ReanimatedTrueSheet`** - Drop-in replacement for `TrueSheet` with automatic position tracking * **`useReanimatedTrueSheet`** - Hook to access the sheet's animated position #### Example: [#example] ```tsx import { ReanimatedTrueSheetProvider, ReanimatedTrueSheet, useReanimatedTrueSheet, } from '@lodev09/react-native-true-sheet/reanimated' import Animated, { useAnimatedStyle, interpolate, Extrapolation } from 'react-native-reanimated' // 1. Wrap your app with the provider const App = () => ( ) // 2. Use ReanimatedTrueSheet instead of TrueSheet const MySheet = () => ( Sheet Content ) // 3. Access the sheet's position for custom animations const MyAnimatedComponent = () => { const { animatedPosition, animatedIndex } = useReanimatedTrueSheet() const positionStyle = useAnimatedStyle(() => ({ transform: [{ translateY: -animatedPosition.value }], })) // Example: Fade in as sheet expands from index 0 to 1 const opacityStyle = useAnimatedStyle(() => ({ opacity: interpolate(animatedIndex.value, [0, 1], [0, 1], Extrapolation.CLAMP) })) return ( This moves with the sheet ) } ``` The `onPositionChange` event now runs on the UI thread (worklet) when using `ReanimatedTrueSheet`. Make sure to add the `'worklet'` directive to your handler if you override it. See the [Reanimated Integration guide](guides/reanimated) for complete examples. ### 6. Native Header Support [#6-native-header-support] Version 3 introduces a new `header` prop for adding fixed headers above your scrollable content. The header is rendered as a native view and is properly accounted for in layout calculations. ```tsx }> ``` This ensures proper scrolling behavior on both iOS and Android when using `ScrollView` or `FlatList` with a header. See the [Header guide](guides/header) for more details. ### 7. Draggable Control [#7-draggable-control] Version 3 introduces the `draggable` prop to disable user dragging entirely. When set to `false`, the sheet becomes static and can only be resized programmatically using the [`resize`](reference/methods#resize) method. ```tsx