@shaquillehinds/smooth-modal
v3.1.0
Published
A simple smooth bottom modal for react native that just works.
Maintainers
Readme
@shaquillehinds/smooth-modal
A comprehensive collection of smooth, performant modal and notification components for React Native. This compilation package provides everything you need for creating beautiful overlays, dropdowns, bottom sheets, menus, and in-app notifications.
📦 What's Included
This package exports all components from the following packages:
- DropdownSelector - Smart, position-aware dropdown selectors
- BottomSheet - Performant bottom sheet with snap points and keyboard handling
- SpotModal - Position-based modals that appear at specific coordinates
- MenuModal - Context menus triggered by press or long-press
- InAppNotification - Beautiful notification system with gesture support
🚀 Installation
npm install @shaquillehinds/smooth-modalor
yarn add @shaquillehinds/smooth-modalPeer Dependencies
All packages require the following peer dependencies:
npm install react-native-reanimated react-native-gesture-handler react-native-svgor
yarn add react-native-reanimated react-native-gesture-handler react-native-svgImportant: Make sure to complete the setup instructions for react-native-reanimated and react-native-gesture-handler.
📚 Package Components
Dropdown Selector
A beautifully animated, fully customizable dropdown selector that intelligently adapts to screen position and just works out of the box.
Features
- 🎯 Smart Positioning - Automatically detects available screen space and renders upward or downward
- 🎨 Fully Customizable - Style every element from the button to individual items
- 🔄 Smooth Animations - Fluid spring and timing animations with configurable parameters
- 🔍 TypeScript Support - Full type safety with generic type support
- 🪶 Lightweight - Minimal dependencies, built on react-native-essentials
Quick Start
import { DropDownSelector } from '@shaquillehinds/smooth-modal';
import { useState } from 'react';
function MyComponent() {
const [selectedValue, setSelectedValue] = useState<string>('apple');
const fruits = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Orange', value: 'orange' },
];
return (
<DropDownSelector
items={fruits}
selectedItem={selectedValue}
onSelect={setSelectedValue}
placeholder="Select a fruit"
/>
);
}Documentation
For complete API reference and advanced usage examples, see the DropdownSelector package documentation.
Bottom Sheet
A performant, highly customizable bottom sheet component with snap points, keyboard awareness, and portal system for rendering above navigation.
Features
- 🎯 Multiple Snap Points - Define custom snap positions as percentages of screen height
- 📱 Keyboard Aware - Intelligent keyboard avoidance with per-input customization
- 🎨 Fully Customizable - Style every aspect from bumper to backdrop
- 🔄 Portal System - Renders at app root level above navigation
- 📜 Scrollable Content - Built-in FlatList and ScrollView components
- ⚡ High Performance - Optimized animations using
useImperativeHandle
Provider Setup
Wrap your app with BottomSheetPortalProvider at the root level:
import { BottomSheetPortalProvider } from '@shaquillehinds/smooth-modal';
export default function App() {
return (
<BottomSheetPortalProvider>
{/* Your app content */}
</BottomSheetPortalProvider>
);
}Quick Start
import React, { useRef, useState } from 'react';
import { View, Text, Button } from 'react-native';
import {
BottomSheetModal,
useBottomSheetRef,
} from '@shaquillehinds/smooth-modal';
import type { BottomModalRefObject } from '@shaquillehinds/smooth-modal';
export default function MyScreen() {
const [showModal, setShowModal] = useState(false);
const bottomSheetRef = useRef<BottomModalRefObject>(null);
return (
<View>
<Button title="Open Bottom Sheet" onPress={() => setShowModal(true)} />
<BottomSheetModal
showModal={showModal}
setShowModal={setShowModal}
ref={bottomSheetRef}
snapPoints={['25%', '50%', '90%']}
>
<View style={{ padding: 20 }}>
<Text>Bottom Sheet Content</Text>
</View>
</BottomSheetModal>
</View>
);
}Documentation
For complete API reference and advanced usage examples, see the BottomSheet package documentation.
Spot Modal
A simple, intelligent position-based modal that renders content at specific screen coordinates. Perfect for context menus, dropdowns, tooltips, and any UI element that needs to appear at a designated spot on the screen.
Features
- 🎯 Coordinate-Based Positioning - Render modals at any X/Y coordinates on the screen
- 🧠 Smart Boundary Detection - Automatically adjusts position to stay within screen bounds
- 📱 Orientation Aware - Handles device rotation and recalculates position accordingly
- 🔌 Portal Support - Render modals at the root level to avoid z-index issues
- ⚡ Smooth Animations - Built with react-native-reanimated for 60fps animations
Provider Setup
Wrap your app with SpotModalPortalProvider at the root level:
import { SpotModalPortalProvider } from '@shaquillehinds/smooth-modal';
export default function App() {
return (
<SpotModalPortalProvider>{/* Your app content */}</SpotModalPortalProvider>
);
}Quick Start
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { SpotModal } from '@shaquillehinds/smooth-modal';
export default function App() {
const [showModal, setShowModal] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
const handlePress = (event) => {
const { pageX, pageY } = event.nativeEvent;
setPosition({ x: pageX, y: pageY });
setShowModal(true);
};
return (
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={handlePress}>
<Text>Tap anywhere on this button</Text>
</TouchableOpacity>
<SpotModal
showModal={showModal}
setShowModal={setShowModal}
pageX={position.x}
pageY={position.y}
backgroundColor="rgba(0, 0, 0, 0.5)"
>
<View
style={{ backgroundColor: 'white', padding: 20, borderRadius: 12 }}
>
<Text>Modal at tap location!</Text>
</View>
</SpotModal>
</View>
);
}Documentation
For complete API reference and advanced usage examples, see the SpotModal package documentation.
Menu Modal
A simple, elegant context menu modal for React Native that appears at the touch location. Perfect for creating contextual menus, dropdown options, and interactive lists triggered by press or long-press gestures.
Features
- 🎯 Position-aware - Opens at exact touch coordinates
- ⚡ Flexible activation - Trigger on press or long-press
- 🎨 Highly customizable - Style every aspect of the menu
- 🔧 TypeScript support - Fully typed for excellent DX
- 🎁 Zero config - Works out of the box, no provider required!
Quick Start
import { MenuModal } from '@shaquillehinds/smooth-modal';
// Works immediately without any setup!
<MenuModal
backgroundColor="#1a1a1a"
options={[
{ title: 'Edit', onOptionPress: () => console.log('Edit') },
{ title: 'Delete', onOptionPress: () => console.log('Delete') },
{ title: 'Share', onOptionPress: () => console.log('Share') },
]}
>
<Text>Press me!</Text>
</MenuModal>;Optional Provider Setup
The MenuModalPortalProvider is optional. The menu modal works out of the box by falling back to React Native's Modal component. However, the portal provider offers better control:
import { MenuModalPortalProvider } from '@shaquillehinds/smooth-modal';
export default function App() {
return (
<MenuModalPortalProvider>{/* Your app content */}</MenuModalPortalProvider>
);
}Documentation
For complete API reference and advanced usage examples, see the MenuModal package documentation.
In-App Notification
A beautiful, customizable, and performant in-app notification system for React Native that just works. Built with React Native Reanimated for smooth 60fps animations and gesture support.
Features
- 🎨 Fully Customizable - Complete control over styling, sizing, and behavior
- 🎭 Flexible Content - Support for both data-driven notifications and custom components
- 🖼️ Image Support - Automatic detection for expo-image, react-native-fast-image, or standard Image
- ⚡ Performant - Built on Reanimated for smooth 60fps animations
- 👆 Gesture Support - Swipe up to dismiss notifications
- 🎪 Queue Management - Smart notification stacking and timing
Provider Setup
Wrap your app with InAppNotificationProvider:
import { InAppNotificationProvider } from '@shaquillehinds/smooth-modal';
export default function App() {
return (
<InAppNotificationProvider>
{/* Your app content */}
</InAppNotificationProvider>
);
}Quick Start
import { useInAppNotification } from '@shaquillehinds/smooth-modal';
function MyComponent() {
const { addNotification } = useInAppNotification();
const showNotification = () => {
addNotification({
title: 'Success!',
message: 'Your action was completed',
imageUrl: 'https://example.com/icon.png',
duration: 3000,
});
};
return <Button title="Show Notification" onPress={showNotification} />;
}Documentation
For complete API reference and advanced usage examples, see the InAppNotification package documentation.
🎨 Styling Philosophy
All packages in this collection are built on @shaquillehinds/react-native-essentials, which provides:
- Predefined border radius sizes (
soft,medium,large) - Shadow utilities with platform-specific handling
- Responsive sizing based on device orientation
- Flexible layout components with intuitive props
🔧 Common Setup
For optimal performance across all packages, configure your project properly:
React Native Reanimated
Add the Babel plugin to your babel.config.js:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};React Native Gesture Handler
Wrap your app entry point:
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
{/* Your providers and app content */}
</GestureHandlerRootView>
);
}Complete Provider Setup Example
Here's a recommended provider setup that works with all packages:
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import {
BottomSheetPortalProvider,
SpotModalPortalProvider,
MenuModalPortalProvider,
InAppNotificationProvider,
} from '@shaquillehinds/'smooth-modal;
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<InAppNotificationProvider>
<BottomSheetPortalProvider>
<SpotModalPortalProvider>
<MenuModalPortalProvider>
{/* Your app content */}
<YourAppContent />
</MenuModalPortalProvider>
</SpotModalPortalProvider>
</BottomSheetPortalProvider>
</InAppNotificationProvider>
</GestureHandlerRootView>
);
}Note: Not all providers are required - only include the ones you're actively using in your app.
🐛 Troubleshooting
Animations Not Working
- Ensure
react-native-reanimatedbabel plugin is configured - Clear Metro cache:
npx react-native start --reset-cache - Rebuild your app after adding the babel plugin
Modals Not Appearing
- Verify you've wrapped your app with the required providers
- Check that peer dependencies are installed correctly
- Ensure gesture handler is properly initialized
Z-Index Issues
- Use portal providers for proper layering
- Place portal providers inside
GestureHandlerRootViewbut outsideNavigationContainer - Verify provider setup order matches the example above
TypeScript Errors
- Ensure you're using compatible versions of peer dependencies
- Check that
@types/reactand@types/react-nativeare up to date - Clear TypeScript cache and restart your IDE
📖 Individual Package Documentation
For detailed documentation on each package, please visit:
- DropdownSelector Documentation
- BottomSheet Documentation
- SpotModal Documentation
- MenuModal Documentation
- InAppNotification Documentation
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request to any of the individual package repositories.
📄 License
MIT © Shaquille Hinds
All packages in this collection are licensed under the MIT License.
🙏 Acknowledgments
Built with:
- @shaquillehinds/react-native-essentials - Core utilities and components
- react-native-reanimated - Smooth animations
- react-native-gesture-handler - Touch handling
- react-native-svg - Vector graphics
📮 Support
- 📧 Email: [email protected]
- 🐛 Report Issues: Check individual package repositories
- 💬 Discussions: GitHub Discussions on individual package repos
Made with ❤️ by Shaquille Hinds
