A React Native library for creating truly native sheet components with smooth animations and native feel across iOS and Android platforms.
- 🎨 Native sheet presentation with platform-specific animations
- 📜 Smart ScrollView integration with automatic content sizing
- 🔧 Customizable appearance (corner radius, backdrop opacity, background color)
- 📱 Support for full-screen and partial height sheets on android
- ⚡ Built for New Architecture (Fabric) only
- 🎯 TypeScript support
- 🔄 Part of @sigmela/router
- 📚 Can be used standalone with react-native-screens
yarn add @sigmela/native-sheetcd ios && pod installThe Android setup is automatically handled by React Native's autolinking.
You can use the library standalone with react-native-screens:
import React, { useState, useRef } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, ScrollView } from 'react-native';
import { ScreenStack, ScreenStackItem } from 'react-native-screens';
import { NativeSheetView, Commands } from '@sigmela/native-sheet';
const SheetContent = ({ onDismiss }) => {
return (
<>
<View testID="sheet-header" style={styles.header}>
<Text style={styles.title}>Sheet Title</Text>
<TouchableOpacity style={styles.button} onPress={onDismiss}>
<Text style={styles.buttonText}>Close Sheet</Text>
</TouchableOpacity>
</View>
<ScrollView testID="sheet-content" style={styles.content}>
<Text style={styles.description}>
This is the sheet content area. You can put any content here including ScrollView, FlatList, or regular Views.
</Text>
</ScrollView>
</>
);
};
const HomeScreen = ({ onOpenSheet }) => {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={onOpenSheet}>
<Text style={styles.buttonText}>Open Sheet</Text>
</TouchableOpacity>
</View>
);
};
export default function App() {
const [showSheet, setShowSheet] = useState(false);
const sheetRef = useRef(null);
const openSheet = () => setShowSheet(true);
const dismissSheet = () => {
if (sheetRef.current) {
Commands.dismiss(sheetRef.current);
}
};
const onSheetDismissed = () => {
setShowSheet(false);
};
return (
<ScreenStack style={styles.flex}>
<ScreenStackItem
screenId="home"
style={StyleSheet.absoluteFill}
headerConfig={{ title: 'Home' }}
>
<HomeScreen onOpenSheet={openSheet} />
</ScreenStackItem>
{showSheet && (
<ScreenStackItem
screenId="sheet"
stackPresentation="transparentModal"
headerConfig={{ hidden: true }}
style={StyleSheet.absoluteFill}
contentStyle={styles.transparentContent}
stackAnimation="none"
onDismissed={onSheetDismissed}
>
<NativeSheetView
ref={sheetRef}
style={styles.flex}
onDismissed={onSheetDismissed}
cornerRadius={18}
containerBackgroundColor="#ffffff"
backdropOpacity={0.5}
>
<SheetContent onDismiss={dismissSheet} />
</NativeSheetView>
</ScreenStackItem>
)}
</ScreenStack>
);
}
const styles = StyleSheet.create({
flex: {
flex: 1,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5f5f5',
},
header: {
padding: 20,
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
},
content: {
flex: 1,
padding: 20,
},
title: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 20,
},
description: {
fontSize: 16,
lineHeight: 24,
color: '#666',
},
button: {
backgroundColor: '#007AFF',
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: '600',
},
transparentContent: {
backgroundColor: 'transparent',
},
});| Prop | Type | Default | Description |
|---|---|---|---|
backdropOpacity |
number |
0.4 |
Opacity of the backdrop behind the sheet |
cornerRadius |
number |
0 |
Corner radius for the sheet container |
fullscreenTopInset |
number |
0 |
Top inset when sheet is in fullscreen mode |
containerBackgroundColor |
ColorValue |
undefined |
Background color of the sheet container |
onAppeared |
() => void |
undefined |
Callback fired when sheet appears |
onDismissed |
() => void |
undefined |
Callback fired when sheet is dismissed |
The library recognizes specific testID values to optimize layout and behavior:
| TestID | Purpose | Description |
|---|---|---|
sheet-header |
Header area | Fixed header section at the top of the sheet |
sheet-content |
Content area | Scrollable content area that automatically adjusts to available space |
<NativeSheetView>
<View testID="sheet-header">
{/* Header content - fixed at top */}
</View>
<ScrollView testID="sheet-content">
{/* Scrollable content */}
</ScrollView>
</NativeSheetView>Programmatically dismiss the sheet.
ref: Reference to the NativeSheetView component
const sheetRef = useRef(null);
const dismissSheet = () => {
if (sheetRef.current) {
Commands.dismiss(sheetRef.current);
}
};The repository includes a complete example app demonstrating both usage patterns:
# Clone the repository
git clone https://github.com/sigmela/native-sheet.git
cd native-sheet
# Install dependencies
yarn install
# Run the example (iOS)
yarn example ios
# Run the example (Android)
yarn example androidSee the contributing guide to learn how to contribute to the repository and the development workflow.
MIT © sigmela