react-native-sheet-transitions v0.1.2
React Native Sheet Transitions π
Beautiful iOS-like sheet transitions for React Native, Expo Go, and Web. Provides smooth, native-feeling custom modal transitions with gesture-based interactions.
Features β¨
- π Smooth scale transitions
- π Gesture-based dismissal with haptic feedback
- π± iOS-like modal animations
- π¨ Customizable animations
- π Two animation modes: incremental & decremental
- π― Border radius sync with gestures
- π Opacity animations
- π Multi-directional dragging support
β οΈ Work in Progress: This package is under active development and not yet recommended for production use. Breaking changes may occur frequently. Feel free to contribute by submitting PRs or reporting issues!
Installation π¦
npm install react-native-sheet-transitions
# or
yarn add react-native-sheet-transitions
# or
bun add react-native-sheet-transitions
Peer Dependencies
npm install react-native-reanimated react-native-gesture-handler
Basic Usage π
- Wrap your app with
SheetProvider
:
import { SheetProvider } from 'react-native-sheet-transitions'
export default function App() {
return (
<SheetProvider>
<Navigation />
</SheetProvider>
)
}
- Use
SheetScreen
in your modal:
import { SheetScreen } from 'react-native-sheet-transitions'
export default function ModalScreen() {
const router = useRouter()
return (
<SheetScreen
onClose={() => router.back()}
dragDirections={{ toBottom: true }}
opacityOnGestureMove={true}
containerRadiusSync={true}
>
<YourContent />
</SheetScreen>
)
}
API Reference π
SheetProvider Props
Prop | Type | Default | Description |
---|---|---|---|
springConfig | SpringConfig | { damping: 15, stiffness: 150, mass: 0.5 } | Spring animation configuration |
resizeType | 'incremental' \| 'decremental' | 'decremental' | Scale animation mode |
enableForWeb | boolean | false | Enable animations on web platform (not recommended) |
SheetScreen Props
Prop | Type | Default | Description |
---|---|---|---|
onClose | () => void | required | Callback when sheet is dismissed |
scaleFactor | number | 0.83 | Scale factor for background content |
dragThreshold | number | 150 | Distance required to trigger dismiss |
springConfig | SpringConfig | { damping: 15, stiffness: 60, mass: 0.6, restDisplacementThreshold: 0.01, restSpeedThreshold: 0.01 } | Spring animation config |
dragDirections | DragDirections | { toBottom: true } | Enabled drag directions |
isScrollable | boolean | false | Enable scroll handling for content |
opacityOnGestureMove | boolean | false | Enable opacity animation during drag |
containerRadiusSync | boolean | true | Sync border radius with drag |
initialBorderRadius | number | 50 | Initial border radius value |
style | ViewStyle | undefined | Additional container styles |
disableSyncScaleOnDragDown | boolean | false | Disable scale sync during drag |
customBackground | ReactNode | undefined | Custom background component with fade animation |
onOpenStart | () => void | undefined | Called when sheet starts opening animation |
onOpenEnd | () => void | undefined | Called when sheet opening animation completes |
onCloseStart | () => void | undefined | Called when user gesture triggers close |
onCloseEnd | () => void | undefined | Called when close animation completes (replaces onClose if provided) |
onBelowThreshold | () => void | undefined | Called when drag goes below threshold after exceeding it |
disableRootScale | boolean | false | Disable background scaling effect |
disableSheetContentResizeOnDragDown | boolean | false | Disable sheet content scaling during drag down |
Types
interface SpringConfig {
damping?: number
stiffness?: number
mass?: number
velocity?: number
}
interface DragDirections {
toTop?: boolean
toBottom?: boolean
toLeft?: boolean
toRight?: boolean
}
Advanced Usage π§
Incremental Scale Mode
Background scales up instead of down:
<SheetProvider resizeType="incremental">
<App />
</SheetProvider>
Custom Animation Config
<SheetScreen
springConfig={{
damping: 15,
stiffness: 120,
mass: 0.8
}}
scaleFactor={0.85}
dragThreshold={100}
opacityOnGestureMove={true}
containerRadiusSync={true}
initialBorderRadius={40}
>
<Content />
</SheetScreen>
Multi-directional Dragging
<SheetScreen
dragDirections={{
toBottom: true,
toLeft: true,
toRight: true
}}
onClose={handleClose}
>
<Content />
</SheetScreen>
Custom Background
You can add a custom background component that fades in/out with the modal:
import { BlurView } from 'expo-blur'
<SheetScreen
customBackground={
<BlurView
intensity={20}
style={StyleSheet.absoluteFill}
/>
}
onClose={handleClose}
>
<Content />
</SheetScreen>
The background component will:
- Fade in when modal opens
- Fade out when modal closes
- Be positioned absolutely behind the modal content
- Not sync opacity with drag gestures
Expo Router Integration π
Configure your modal screen:
// app/_layout.tsx
import { Stack } from 'expo-router'
import { SheetProvider } from 'react-native-sheet-transitions'
export default function Layout() {
return (
<SheetProvider>
<Stack>
<Stack.Screen name="index" />
<Stack.Screen
name="modal"
options={{
presentation: 'transparentModal',
contentStyle: { backgroundColor: 'transparent' }
}}
/>
</Stack>
</SheetProvider>
)
}
Contributing π€
Pull requests are welcome! For major changes:
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Open a pull request
Lifecycle Callbacks
The SheetScreen component provides several callbacks for precise control:
interface SheetScreenProps {
// Called when sheet starts opening animation
onOpenStart?: () => void
// Called when sheet opening animation completes
onOpenEnd?: () => void
// Called when user drags above threshold
onCloseStart?: () => void
// Called when user drags below threshold
onBelowThreshold?: () => void
// Called when close animation completes
onCloseEnd?: () => void
}
Example with Haptic Feedback
<SheetScreen
onCloseStart={() => {
// Warn user they can release to close
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning)
}}
onBelowThreshold={() => {
// Reset state when going below threshold
}}
onCloseEnd={() => {
// Success haptic when sheet closes
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success)
router.back()
}}
>
{/* content */}
</SheetScreen>
Platform Specific Behavior π±
Background Scaling
The background scaling effect (where the previous screen scales down when the sheet opens) is:
- β Enabled by default on iOS
- β Disabled by default on Android and Web
- Can be disabled on iOS using
disableRootScale={true}
<SheetScreen
disableRootScale={true} // Disable background scaling even on iOS
onClose={handleClose}
>
<Content />
</SheetScreen>
Web Platform Support β οΈ
By default, sheet transitions are disabled on web platforms for better UX and accessibility. Web modals should follow web platform conventions.
If you need to enable animations on web:
<SheetProvider enableForWeb={true}>
<App />
</SheetProvider>
Note: Enabling sheet transitions on web is not recommended as it can:
- Interfere with native web accessibility features
- Create inconsistent UX across different browsers
- Impact performance on lower-end devices
- Break expected web modal behaviors
Consider using native web modals or dialogs for better user experience on web platforms.
Roadmap πΊοΈ
High Priority
- Fix Scrolling gesture handling and momentum issues
- Multiple Portal support for nested sheets
- iOS-like sheet detents (snap points)
- Configurable small, medium, large positions
- Custom snap point values
- Default snap point configuration
- Smooth animations between detents
- Gesture-based snapping behavior
Plans
- Enhanced gesture controls
- Velocity-based dismissal
- Directional lock
- Accessibility improvements
- Screen reader support
- Reduced motion preferences
- Focus support
- More animations
- Shared element transitions
- Better web support
- Keyboard navigation
- Focus trapping
License π
MIT Β© saulamsal