react-native-keyboard-aware-modal
v0.2.2
Published
A smooth animated modal which is keyboard aware and can be used as a controller
Maintainers
Readme
react-native-keyboard-aware-modal
A smooth animated modal component for React Native that is keyboard-aware and can be used as a controller. Built with react-native-reanimated and react-native-gesture-handler for performant animations and gestures.
Features
- 🎹 Keyboard Aware - Automatically adjusts when keyboard appears/disappears
- 🎨 Smooth Animations - Customizable spring and timing animations
- 👆 Draggable - Drag to dismiss with snap points support
- 🎛️ Modal Controller - Context-based API for easy modal management
- 🎯 Flexible Usage - Use with ModalController or directly as a component
- 🎨 Highly Customizable - Custom headers, styles, animations, and more
- 📱 TypeScript Support - Full TypeScript definitions included
- ⚡ Performant - Built with Reanimated for 60fps animations
Installation
npm install react-native-keyboard-aware-modalor
yarn add react-native-keyboard-aware-modalPeer Dependencies
This library requires the following peer dependencies:
npm install react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-workletsImportant: Make sure to follow the setup instructions for:
Usage
Using ModalController (Recommended)
The ModalController provides a context-based API for managing modals throughout your app.
1. Wrap your app with ModalControllerProvider
import { ModalControllerProvider } from 'react-native-keyboard-aware-modal';
function App() {
return (
<ModalControllerProvider>
{/* Your app content */}
</ModalControllerProvider>
);
}2. Use the useModal hook to show modals
import { useModal } from 'react-native-keyboard-aware-modal';
import { View, Text, TouchableOpacity } from 'react-native';
function MyComponent() {
const { showModal } = useModal();
const openModal = () => {
showModal(
() => (
<View style={{ padding: 20 }}>
<Text>Hello from modal!</Text>
</View>
),
{
// Optional configuration
backgroundColor: 'white',
borderRadius: 20,
keyboardAware: true,
}
);
};
return (
<TouchableOpacity onPress={openModal}>
<Text>Open Modal</Text>
</TouchableOpacity>
);
}Using KeyboardAwareModal Directly
You can also use KeyboardAwareModal directly without the controller context:
import { KeyboardAwareModal } from 'react-native-keyboard-aware-modal';
import { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
function MyComponent() {
const [visible, setVisible] = useState(false);
return (
<>
<TouchableOpacity onPress={() => setVisible(true)}>
<Text>Open Modal</Text>
</TouchableOpacity>
<KeyboardAwareModal
visible={visible}
onClose={() => setVisible(false)}
keyboardAware={true}
backgroundColor="white"
borderRadius={20}>
<View style={{ padding: 20 }}>
<Text>Hello from modal!</Text>
</View>
</KeyboardAwareModal>
</>
);
}Examples
Check out the examples folder for comprehensive examples:
- BasicModalExample - Basic modal usage with different configurations
- CustomHeaderExample - Creating custom headers
- DraggableModalExample - Draggable modals with snap points
- AnimationCustomizationExample - Customizing animations
- KeyboardAwareExample - Keyboard-aware forms
- DirectModalExample - Direct component usage
To run the examples:
cd example
yarn install
yarn ios # or yarn androidAPI Reference
ModalControllerProvider
Provider component that wraps your app to enable modal controller functionality.
<ModalControllerProvider>
{children}
</ModalControllerProvider>useModal Hook
Returns an object with showModal and hideModal functions.
const { showModal, hideModal } = useModal();showModal(renderContent, config?)
renderContent: A function that returns the modal content (ReactNode)config?: Optional ModalConfig object
hideModal()
Closes the currently visible modal.
KeyboardAwareModal Props
| Prop | Type | Description | Default |
|------|------|-------------|---------|
| visible | boolean | Controls modal visibility | required |
| onClose | () => void | Callback when modal should close | required |
| children | ReactNode | Modal content | required |
| headerView | ReactNode | Custom header component | undefined |
| snapPoints | number[] | Array of heights (0-1) where modal can snap | [0] |
| initialSnapIndex | number | Initial snap point index | 0 |
| dragHandle | boolean | Show drag handle indicator | false |
| dragHandleStyle | ViewStyle | Custom drag handle style | undefined |
| extraClosingThreshold | number | Extra pixels to drag before closing | 40 |
| draggable | boolean | Enable drag to dismiss | true |
| keyboardAware | boolean | Automatically adjust for keyboard | true |
| backgroundColor | string | Modal background color | 'white' |
| backdropColor | string | Backdrop color | 'rgba(0, 0, 0, 0.5)' |
| backdropOpacity | number | Backdrop opacity (0-1) | 1 |
| showBackdrop | boolean | Show backdrop overlay | true |
| roundedCorners | boolean | Round top corners | true |
| borderRadius | number | Border radius for top corners | 20 |
| openingAnimation | ModalAnimationConfig | Custom opening animation | undefined |
| closingAnimation | ModalAnimationConfig | Custom closing animation | undefined |
| backdropAnimation | BackdropAnimationConfig | Custom backdrop animation | undefined |
| mainContainerStyle | ViewStyle | Main container style | undefined |
| modalContentStyle | ViewStyle | Modal content wrapper style | undefined |
| headerStyle | ViewStyle | Header container style | undefined |
| contentStyle | ViewStyle | Content container style | undefined |
| contentContainerStyle | ViewStyle | ScrollView content container style | undefined |
| maxModalHeight | number | Maximum height for the modal content | undefined |
| layoutAnimation | LayoutAnimation | Custom layout animation for the modal container | LinearTransition.springify().damping(25).stiffness(120).duration(500) |
ModalConfig
Configuration object for showModal:
interface ModalConfig {
headerView?: ReactNode;
snapPoints?: number[];
initialSnapIndex?: number;
dragHandle?: boolean;
dragHandleStyle?: ViewStyle;
extraClosingThreshold?: number;
draggable?: boolean;
keyboardAware?: boolean;
backgroundColor?: string;
backdropColor?: string;
backdropOpacity?: number;
showBackdrop?: boolean;
roundedCorners?: boolean;
borderRadius?: number;
openingAnimation?: ModalAnimationConfig;
closingAnimation?: ModalAnimationConfig;
backdropAnimation?: BackdropAnimationConfig;
mainContainerStyle?: ViewStyle;
modalContentStyle?: ViewStyle;
headerStyle?: ViewStyle;
contentStyle?: ViewStyle;
contentContainerStyle?: ViewStyle;
maxModalHeight?: number;
layoutAnimation?: LayoutAnimation;
}Animation Configuration
ModalAnimationConfig
interface ModalAnimationConfig {
type?: 'spring' | 'timing';
springConfig?: {
damping?: number;
stiffness?: number;
mass?: number;
overshootClamping?: boolean;
restDisplacementThreshold?: number;
restSpeedThreshold?: number;
velocity?: number;
};
timingConfig?: {
duration?: number;
easing?: EasingFunction;
};
}BackdropAnimationConfig
interface BackdropAnimationConfig {
duration?: number;
easing?: EasingFunction;
}Advanced Examples
Draggable Modal with Snap Points
showModal(
() => (
<View style={{ padding: 20 }}>
<Text>Drag me up and down!</Text>
</View>
),
{
snapPoints: [0.5, 0.75, 1], // 50%, 75%, 100% of screen height
initialSnapIndex: 1, // Start at 100%
dragHandle: true,
}
);Custom Animation
showModal(
() => <View>...</View>,
{
openingAnimation: {
type: 'spring',
springConfig: {
damping: 20,
stiffness: 90,
},
},
closingAnimation: {
type: 'timing',
timingConfig: {
duration: 200,
},
},
}
);Custom Header
showModal(
() => <View>...</View>,
{
headerView: (
<View style={{ padding: 16, backgroundColor: '#f0f0f0' }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
Custom Header
</Text>
</View>
),
}
);Contributing
License
MIT
Made with create-react-native-library
