An enhanced React Native modal component with animations, customizable backdrop, and swipe-to-dismiss functionality
npx @tessl/cli install tessl/npm-react-native-modal@13.0.00
# React Native Modal
1
2
React Native Modal is an enhanced, animated, and highly customizable modal component for React Native applications. It extends the original React Native Modal component by adding smooth enter/exit animations, customizable backdrop appearance, swipe-to-dismiss functionality, and comprehensive event handling with device rotation support and keyboard avoidance.
3
4
## Package Information
5
6
- **Package Name**: react-native-modal
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install react-native-modal` or `yarn add react-native-modal`
10
11
## Core Imports
12
13
```typescript
14
import Modal from "react-native-modal";
15
```
16
17
For named imports:
18
19
```typescript
20
import {
21
ReactNativeModal,
22
ModalProps,
23
OnSwipeCompleteParams,
24
AnimationEvent,
25
Animations,
26
SupportedAnimation,
27
Orientation,
28
Direction,
29
PresentationStyle,
30
OnOrientationChange,
31
GestureResponderEvent
32
} from "react-native-modal";
33
```
34
35
CommonJS:
36
37
```javascript
38
const Modal = require("react-native-modal");
39
```
40
41
For TypeScript usage with React Native types:
42
43
```typescript
44
import { StyleProp, ViewStyle, NativeSyntheticEvent, NativeTouchEvent } from "react-native";
45
import { PanResponderGestureState } from "react-native";
46
```
47
48
## Basic Usage
49
50
```typescript
51
import React, { useState } from "react";
52
import { Button, Text, View } from "react-native";
53
import Modal from "react-native-modal";
54
55
function ModalExample() {
56
const [isModalVisible, setModalVisible] = useState(false);
57
58
const toggleModal = () => {
59
setModalVisible(!isModalVisible);
60
};
61
62
return (
63
<View style={{ flex: 1 }}>
64
<Button title="Show modal" onPress={toggleModal} />
65
66
<Modal isVisible={isModalVisible}>
67
<View style={{ flex: 1, backgroundColor: "white" }}>
68
<Text>Hello! I am a modal.</Text>
69
<Button title="Hide modal" onPress={toggleModal} />
70
</View>
71
</Modal>
72
</View>
73
);
74
}
75
```
76
77
## Architecture
78
79
React Native Modal is built around several key components:
80
81
- **ReactNativeModal Component**: Main modal class extending React.Component with enhanced functionality
82
- **Animation System**: Built on react-native-animatable with custom slide animations and timing controls
83
- **Gesture Handling**: PanResponder-based swipe detection with configurable directions and thresholds
84
- **Backdrop Management**: Customizable backdrop with opacity transitions and custom backdrop support
85
- **State Management**: Internal state tracking for visibility, dimensions, and animation states
86
- **Event System**: Comprehensive lifecycle callbacks for show/hide/swipe events
87
88
## Capabilities
89
90
### Modal Component
91
92
The main modal component providing enhanced functionality over React Native's built-in Modal.
93
94
```typescript { .api }
95
/**
96
* Enhanced React Native modal component with animations and gesture support
97
*/
98
class ReactNativeModal extends React.Component<ModalProps, State> {
99
static defaultProps: typeof defaultProps;
100
}
101
102
/**
103
* Default export - same as ReactNativeModal class
104
*/
105
export default ReactNativeModal;
106
```
107
108
### Modal Props Interface
109
110
Complete props interface for configuring modal behavior and appearance.
111
112
```typescript { .api }
113
type ModalProps = ViewProps & {
114
children: React.ReactNode;
115
116
// Swipe Gesture Props
117
onSwipeStart?: (gestureState: PanResponderGestureState) => void;
118
onSwipeMove?: (percentageShown: number, gestureState: PanResponderGestureState) => void;
119
onSwipeComplete?: (params: OnSwipeCompleteParams, gestureState: PanResponderGestureState) => void;
120
onSwipeCancel?: (gestureState: PanResponderGestureState) => void;
121
style?: StyleProp<ViewStyle>;
122
swipeDirection?: Direction | Array<Direction>;
123
124
// Inherited React Native Modal Props
125
onDismiss?: () => void;
126
onShow?: () => void;
127
hardwareAccelerated?: boolean;
128
onOrientationChange?: OnOrientationChange;
129
presentationStyle?: PresentationStyle;
130
131
// Additional Modal Props (defaults provided by defaultProps)
132
useNativeDriverForBackdrop?: boolean;
133
} & typeof defaultProps;
134
135
// All properties from defaultProps are automatically available as optional props:
136
// animationIn, animationInTiming, animationOut, animationOutTiming, avoidKeyboard,
137
// coverScreen, hasBackdrop, backdropColor, backdropOpacity, backdropTransitionInTiming,
138
// backdropTransitionOutTiming, customBackdrop, useNativeDriver, deviceHeight, deviceWidth,
139
// hideModalContentWhileAnimating, propagateSwipe, isVisible, panResponderThreshold,
140
// swipeThreshold, onModalShow, onModalWillShow, onModalHide, onModalWillHide,
141
// onBackdropPress, onBackButtonPress, scrollTo, scrollOffset, scrollOffsetMax,
142
// scrollHorizontal, statusBarTranslucent, supportedOrientations
143
```
144
145
### Swipe Complete Parameters
146
147
Parameters passed to the onSwipeComplete callback when a swipe gesture completes.
148
149
```typescript { .api }
150
interface OnSwipeCompleteParams {
151
swipingDirection: Direction;
152
}
153
```
154
155
### Animation System
156
157
```typescript { .api }
158
/**
159
* Initializes custom slide animations, overriding react-native-animatable defaults
160
*/
161
function initializeAnimations(): void;
162
163
/**
164
* Builds animation configuration objects, handling custom animation definitions
165
*/
166
function buildAnimations(options: {
167
animationIn: Animation | CustomAnimation;
168
animationOut: Animation | CustomAnimation;
169
}): Animations;
170
171
/**
172
* Utility function for animation calculations: returns -(x - 1)
173
*/
174
function reversePercentage(x: number): number;
175
176
/**
177
* Creates slide translation animation objects for react-native-animatable
178
*/
179
function makeSlideTranslation(
180
translationType: string,
181
fromValue: number,
182
toValue: number
183
): CustomAnimation;
184
```
185
186
## Types
187
188
### Core Types
189
190
```typescript { .api }
191
type SupportedAnimation = Animation | CustomAnimation;
192
193
interface Animations {
194
animationIn: string;
195
animationOut: string;
196
}
197
198
type Orientation =
199
| "portrait"
200
| "portrait-upside-down"
201
| "landscape"
202
| "landscape-left"
203
| "landscape-right";
204
205
type Direction = "up" | "down" | "left" | "right";
206
207
type PresentationStyle =
208
| "fullScreen"
209
| "pageSheet"
210
| "formSheet"
211
| "overFullScreen";
212
213
type AnimationEvent = (...args: any[]) => void;
214
215
type OnOrientationChange = (orientation: NativeSyntheticEvent<any>) => void;
216
217
type OrNull<T> = null | T;
218
219
interface GestureResponderEvent extends NativeSyntheticEvent<NativeTouchEvent> {}
220
221
interface PanResponderGestureState {
222
stateID: number;
223
moveX: number;
224
moveY: number;
225
x0: number;
226
y0: number;
227
dx: number;
228
dy: number;
229
vx: number;
230
vy: number;
231
numberActiveTouches: number;
232
}
233
234
// React Native types used in the API
235
type StyleProp<T> = T | T[] | null | undefined;
236
type ViewStyle = Record<string, any>;
237
interface ViewProps {
238
style?: StyleProp<ViewStyle>;
239
testID?: string;
240
accessible?: boolean;
241
accessibilityLabel?: string;
242
accessibilityHint?: string;
243
accessibilityRole?: string;
244
accessibilityState?: Record<string, any>;
245
accessibilityValue?: Record<string, any>;
246
onLayout?: (event: any) => void;
247
pointerEvents?: 'none' | 'box-none' | 'box-only' | 'auto';
248
removeClippedSubviews?: boolean;
249
renderToHardwareTextureAndroid?: boolean;
250
shouldRasterizeIOS?: boolean;
251
collapsable?: boolean;
252
needsOffscreenAlphaCompositing?: boolean;
253
onStartShouldSetResponder?: (event: any) => boolean;
254
onMoveShouldSetResponder?: (event: any) => boolean;
255
onResponderGrant?: (event: any) => void;
256
onResponderMove?: (event: any) => void;
257
onResponderRelease?: (event: any) => void;
258
onResponderTerminate?: (event: any) => void;
259
onResponderTerminationRequest?: (event: any) => boolean;
260
onStartShouldSetResponderCapture?: (event: any) => boolean;
261
onMoveShouldSetResponderCapture?: (event: any) => boolean;
262
}
263
interface NativeSyntheticEvent<T> {
264
nativeEvent: T;
265
currentTarget: number;
266
target: number;
267
bubbles?: boolean;
268
cancelable?: boolean;
269
defaultPrevented?: boolean;
270
eventPhase?: number;
271
isTrusted?: boolean;
272
preventDefault(): void;
273
stopPropagation(): void;
274
persist(): void;
275
timeStamp: number;
276
type: string;
277
}
278
interface NativeTouchEvent {
279
changedTouches: Array<NativeTouchEvent>;
280
identifier: string;
281
locationX: number;
282
locationY: number;
283
pageX: number;
284
pageY: number;
285
target: string;
286
timestamp: number;
287
touches: Array<NativeTouchEvent>;
288
}
289
```
290
291
### Default Props Values
292
293
```typescript { .api }
294
const defaultProps = {
295
animationIn: "slideInUp" as Animation | CustomAnimation,
296
animationInTiming: 300,
297
animationOut: "slideOutDown" as Animation | CustomAnimation,
298
animationOutTiming: 300,
299
avoidKeyboard: false,
300
coverScreen: true,
301
hasBackdrop: true,
302
backdropColor: "black",
303
backdropOpacity: 0.7,
304
backdropTransitionInTiming: 300,
305
backdropTransitionOutTiming: 300,
306
customBackdrop: null,
307
useNativeDriver: false,
308
deviceHeight: null,
309
deviceWidth: null,
310
hideModalContentWhileAnimating: false,
311
propagateSwipe: false,
312
isVisible: false,
313
panResponderThreshold: 4,
314
swipeThreshold: 100,
315
onModalShow: () => null,
316
onModalWillShow: () => null,
317
onModalHide: () => null,
318
onModalWillHide: () => null,
319
onBackdropPress: () => null,
320
onBackButtonPress: () => null,
321
scrollTo: null,
322
scrollOffset: 0,
323
scrollOffsetMax: 0,
324
scrollHorizontal: false,
325
statusBarTranslucent: false,
326
supportedOrientations: ["portrait", "landscape"] as Orientation[]
327
};
328
```
329
330
## Usage Examples
331
332
### Basic Modal with Animation
333
334
```typescript
335
import React, { useState } from "react";
336
import { Button, Text, View } from "react-native";
337
import Modal from "react-native-modal";
338
339
function AnimatedModal() {
340
const [isVisible, setVisible] = useState(false);
341
342
return (
343
<View style={{ flex: 1 }}>
344
<Button title="Show Modal" onPress={() => setVisible(true)} />
345
346
<Modal
347
isVisible={isVisible}
348
animationIn="slideInUp"
349
animationOut="slideOutDown"
350
animationInTiming={600}
351
animationOutTiming={600}
352
onBackdropPress={() => setVisible(false)}>
353
<View style={{ backgroundColor: "white", padding: 20 }}>
354
<Text>This is a modal with custom animations!</Text>
355
<Button title="Close" onPress={() => setVisible(false)} />
356
</View>
357
</Modal>
358
</View>
359
);
360
}
361
```
362
363
### Swipeable Modal
364
365
```typescript
366
import React, { useState } from "react";
367
import { Text, View } from "react-native";
368
import Modal from "react-native-modal";
369
370
function SwipeableModal() {
371
const [isVisible, setVisible] = useState(true);
372
373
return (
374
<Modal
375
isVisible={isVisible}
376
swipeDirection={["up", "down"]}
377
swipeThreshold={100}
378
onSwipeComplete={() => setVisible(false)}
379
onSwipeStart={(gestureState) => console.log("Swipe started")}
380
onSwipeMove={(percentageShown) => console.log("Swipe progress:", percentageShown)}>
381
<View style={{ backgroundColor: "white", padding: 20 }}>
382
<Text>Swipe up or down to dismiss this modal</Text>
383
</View>
384
</Modal>
385
);
386
}
387
```
388
389
### Custom Backdrop Modal
390
391
```typescript
392
import React, { useState } from "react";
393
import { Text, View, ImageBackground } from "react-native";
394
import Modal from "react-native-modal";
395
396
function CustomBackdropModal() {
397
const [isVisible, setVisible] = useState(true);
398
399
const CustomBackdrop = () => (
400
<ImageBackground
401
source={{ uri: "https://example.com/background.jpg" }}
402
style={{ flex: 1 }}
403
blurRadius={5}
404
/>
405
);
406
407
return (
408
<Modal
409
isVisible={isVisible}
410
customBackdrop={<CustomBackdrop />}
411
onBackdropPress={() => setVisible(false)}>
412
<View style={{ backgroundColor: "white", padding: 20 }}>
413
<Text>Modal with custom backdrop</Text>
414
</View>
415
</Modal>
416
);
417
}
418
```
419
420
### Modal with Keyboard Avoidance
421
422
```typescript
423
import React, { useState } from "react";
424
import { TextInput, Button, View } from "react-native";
425
import Modal from "react-native-modal";
426
427
function KeyboardModal() {
428
const [isVisible, setVisible] = useState(true);
429
const [text, setText] = useState("");
430
431
return (
432
<Modal
433
isVisible={isVisible}
434
avoidKeyboard={true}
435
onBackdropPress={() => setVisible(false)}>
436
<View style={{ backgroundColor: "white", padding: 20 }}>
437
<TextInput
438
value={text}
439
onChangeText={setText}
440
placeholder="Type something..."
441
style={{ borderWidth: 1, padding: 10, marginBottom: 10 }}
442
/>
443
<Button title="Close" onPress={() => setVisible(false)} />
444
</View>
445
</Modal>
446
);
447
}
448
```
449
450
### Full Screen Modal
451
452
```typescript
453
import React, { useState } from "react";
454
import { Text, Button, View } from "react-native";
455
import Modal from "react-native-modal";
456
457
function FullScreenModal() {
458
const [isVisible, setVisible] = useState(true);
459
460
return (
461
<Modal
462
isVisible={isVisible}
463
style={{ margin: 0 }} // Remove default margin for full screen
464
animationIn="slideInRight"
465
animationOut="slideOutRight">
466
<View style={{ flex: 1, backgroundColor: "white", padding: 20 }}>
467
<Text>Full screen modal</Text>
468
<Button title="Close" onPress={() => setVisible(false)} />
469
</View>
470
</Modal>
471
);
472
}
473
```