Hybrid BottomSheet for React Native (Expo + RN CLI, TSX + JSX)
npm install reactnative-hybrid-bottomsheet
A lightweight, dependency-free hybrid BottomSheet for React Native.
Supports Expo, React Native CLI, iOS, Android, TSX, and JSX.
---
Most popular bottom sheet libraries depend on Reanimated and Gesture Handler.
This one does not ā making it perfect for:
- Expo Managed Workflow
- Lightweight apps
- Simpler projects
- Beginners learning bottom sheet behavior
ā
Zero native setup
ā
Zero additional dependencies
ā
Works everywhere out-of-the-box
---
- Automatic height based on content
- minHeight / maxHeight / fullScreen
- Swipe-down gesture to close
- Tap backdrop to close
- Smart scrollable content (only when needed)
- Snap points (snapPoints) + snapToIndex()
- initialPosition / initialSnap
- Custom drag handle + dragHandlePosition
- cornerRadius customization
- Imperative API (open, close, snapToIndex)
- Fully typed (TypeScript)
---
``bash`
npm install reactnative-hybrid-bottomsheetor
yarn add reactnative-hybrid-bottomsheet
---
`tsx
import React, { useRef } from "react";
import { View, Button, Text } from "react-native";
import {
BottomSheet,
type BottomSheetMethods,
} from "reactnative-hybrid-bottomsheet";
export default function App() {
const sheetRef = useRef
return (
minHeight="20%"
maxHeight="80%"
snapPoints={["20%", "50%", "80%"]}
initialSnap={1}
scrollable
backdropOpacity={0.5}
dragHandlePosition="top"
cornerRadius={24}
onOpen={() => console.log("Sheet opened")}
onClose={() => console.log("Sheet closed")}
>
Hybrid BottomSheet š
);
}
`
---
`jsx
import React, { useRef } from "react";
import { View, Button, Text } from "react-native";
import { BottomSheet } from "reactnative-hybrid-bottomsheet";
export default function DemoScreen() {
const sheetRef = useRef(null);
return (
fullScreen
enablePanDownToClose
backdropOpacity={0.6}
>
Full-screen BottomSheet
);
}
`
---
`ts
type DragHandlePosition = "top" | "inside" | "hidden";
interface BottomSheetProps {
children?: React.ReactNode;
onClose?: () => void;
onOpen?: () => void;
backdropOpacity?: number;
backdropColor?: string;
enableBackdropPress?: boolean;
disableBackdropPress?: boolean;
animationDuration?: number;
maxHeight?: number | string;
minHeight?: number | string;
initialPosition?: number | string;
fullScreen?: boolean;
expandOnContentChange?: boolean;
autoCloseWhenEmpty?: boolean;
scrollable?: boolean;
snapPoints?: (number | string)[];
initialSnap?: number;
enablePanDownToClose?: boolean;
gestureSensitivity?: number;
handleComponent?: React.ReactNode;
dragHandlePosition?: DragHandlePosition;
cornerRadius?: number;
containerStyle?: StyleProp
contentContainerStyle?: StyleProp
}
`
---
| Prop | Type | Default | Description |
|-------------------------|---------------------------|---------------------------------|-------------|
| children | ReactNode | ā | Content inside the sheet |onClose
| | () => void | undefined | Called when sheet fully closes |onOpen
| | () => void | undefined | Called when sheet fully opens |backdropOpacity
| | number | 0.4 | Backdrop darkness |backdropColor
| | string | "rgba(0,0,0,0.4)" | Backdrop color |enableBackdropPress
| | boolean | true | Tap outside to close |disableBackdropPress
| | boolean | false | Force-disable backdrop press |animationDuration
| | number | 300 | Open/close animation time (ms) |maxHeight
| | number \| string | SCREEN_HEIGHT (or fullScreen) | Max height allowed |minHeight
| | number \| string | 0 | Minimum sheet height |initialPosition
| | number \| string | 0 | Initial translateY offset when opening (ignored if snapPoints) |fullScreen
| | boolean | false | If true, sheet uses full screen height |expandOnContentChange
| | boolean | false | Animate height when content size changes |autoCloseWhenEmpty
| | boolean | false | Automatically close when content becomes empty |scrollable
| | boolean | false | Enable smart ScrollView for content |snapPoints
| | (number \| string)[] | [] | Snap offsets (like ["20%", "50%", "80%"]) |initialSnap
| | number | 0 | Initial snap index |enablePanDownToClose
| | boolean | true | Allow swipe-down to close |gestureSensitivity
| | number | 1 | Lower = easier to close via swipe |handleComponent
| | ReactNode | default bar | Custom drag handle content |dragHandlePosition
| | "top" \| "inside" \| "hidden" | "top" | Where to show drag handle |cornerRadius
| | number | 20 | Top corner radius |containerStyle
| | StyleProp | undefined | Style override for sheet container |contentContainerStyle
| | StyleProp | undefined | Style override for inner content |
---
`ts`
interface BottomSheetMethods {
open(): void;
close(): void;
snapToIndex?: (index: number) => void;
}
---
Add your GIF at:
``
/assets/demo.gif
---
`bash`
npm install
npm run build
npm pack
---
`bash``
npm version patch
npm run build
npm publish
---
MIT Ā© 2025 Pravin Kumar