or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-react-native-modal

An enhanced React Native modal component with animations, customizable backdrop, and swipe-to-dismiss functionality

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/react-native-modal@13.0.x

To install, run

npx @tessl/cli install tessl/npm-react-native-modal@13.0.0

index.mddocs/

React Native Modal

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.

Package Information

  • Package Name: react-native-modal
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install react-native-modal or yarn add react-native-modal

Core Imports

import Modal from "react-native-modal";

For named imports:

import { 
  ReactNativeModal, 
  ModalProps, 
  OnSwipeCompleteParams,
  AnimationEvent,
  Animations,
  SupportedAnimation,
  Orientation,
  Direction,
  PresentationStyle,
  OnOrientationChange,
  GestureResponderEvent
} from "react-native-modal";

CommonJS:

const Modal = require("react-native-modal");

For TypeScript usage with React Native types:

import { StyleProp, ViewStyle, NativeSyntheticEvent, NativeTouchEvent } from "react-native";
import { PanResponderGestureState } from "react-native";

Basic Usage

import React, { useState } from "react";
import { Button, Text, View } from "react-native";
import Modal from "react-native-modal";

function ModalExample() {
  const [isModalVisible, setModalVisible] = useState(false);

  const toggleModal = () => {
    setModalVisible(!isModalVisible);
  };

  return (
    <View style={{ flex: 1 }}>
      <Button title="Show modal" onPress={toggleModal} />
      
      <Modal isVisible={isModalVisible}>
        <View style={{ flex: 1, backgroundColor: "white" }}>
          <Text>Hello! I am a modal.</Text>
          <Button title="Hide modal" onPress={toggleModal} />
        </View>
      </Modal>
    </View>
  );
}

Architecture

React Native Modal is built around several key components:

  • ReactNativeModal Component: Main modal class extending React.Component with enhanced functionality
  • Animation System: Built on react-native-animatable with custom slide animations and timing controls
  • Gesture Handling: PanResponder-based swipe detection with configurable directions and thresholds
  • Backdrop Management: Customizable backdrop with opacity transitions and custom backdrop support
  • State Management: Internal state tracking for visibility, dimensions, and animation states
  • Event System: Comprehensive lifecycle callbacks for show/hide/swipe events

Capabilities

Modal Component

The main modal component providing enhanced functionality over React Native's built-in Modal.

/**
 * Enhanced React Native modal component with animations and gesture support
 */
class ReactNativeModal extends React.Component<ModalProps, State> {
  static defaultProps: typeof defaultProps;
}

/**
 * Default export - same as ReactNativeModal class
 */
export default ReactNativeModal;

Modal Props Interface

Complete props interface for configuring modal behavior and appearance.

type ModalProps = ViewProps & {
  children: React.ReactNode;
  
  // Swipe Gesture Props
  onSwipeStart?: (gestureState: PanResponderGestureState) => void;
  onSwipeMove?: (percentageShown: number, gestureState: PanResponderGestureState) => void;
  onSwipeComplete?: (params: OnSwipeCompleteParams, gestureState: PanResponderGestureState) => void;
  onSwipeCancel?: (gestureState: PanResponderGestureState) => void;
  style?: StyleProp<ViewStyle>;
  swipeDirection?: Direction | Array<Direction>;
  
  // Inherited React Native Modal Props
  onDismiss?: () => void;
  onShow?: () => void;
  hardwareAccelerated?: boolean;
  onOrientationChange?: OnOrientationChange;
  presentationStyle?: PresentationStyle;
  
  // Additional Modal Props (defaults provided by defaultProps)
  useNativeDriverForBackdrop?: boolean;
} & typeof defaultProps;

// All properties from defaultProps are automatically available as optional props:
// animationIn, animationInTiming, animationOut, animationOutTiming, avoidKeyboard,
// coverScreen, hasBackdrop, backdropColor, backdropOpacity, backdropTransitionInTiming,
// backdropTransitionOutTiming, customBackdrop, useNativeDriver, deviceHeight, deviceWidth,
// hideModalContentWhileAnimating, propagateSwipe, isVisible, panResponderThreshold,
// swipeThreshold, onModalShow, onModalWillShow, onModalHide, onModalWillHide,
// onBackdropPress, onBackButtonPress, scrollTo, scrollOffset, scrollOffsetMax,
// scrollHorizontal, statusBarTranslucent, supportedOrientations

Swipe Complete Parameters

Parameters passed to the onSwipeComplete callback when a swipe gesture completes.

interface OnSwipeCompleteParams {
  swipingDirection: Direction;
}

Animation System

/**
 * Initializes custom slide animations, overriding react-native-animatable defaults
 */
function initializeAnimations(): void;

/**
 * Builds animation configuration objects, handling custom animation definitions
 */
function buildAnimations(options: {
  animationIn: Animation | CustomAnimation;
  animationOut: Animation | CustomAnimation;
}): Animations;

/**
 * Utility function for animation calculations: returns -(x - 1)
 */
function reversePercentage(x: number): number;

/**
 * Creates slide translation animation objects for react-native-animatable
 */
function makeSlideTranslation(
  translationType: string,
  fromValue: number,
  toValue: number
): CustomAnimation;

Types

Core Types

type SupportedAnimation = Animation | CustomAnimation;

interface Animations {
  animationIn: string;
  animationOut: string;
}

type Orientation = 
  | "portrait" 
  | "portrait-upside-down" 
  | "landscape" 
  | "landscape-left" 
  | "landscape-right";

type Direction = "up" | "down" | "left" | "right";

type PresentationStyle = 
  | "fullScreen" 
  | "pageSheet" 
  | "formSheet" 
  | "overFullScreen";

type AnimationEvent = (...args: any[]) => void;

type OnOrientationChange = (orientation: NativeSyntheticEvent<any>) => void;

type OrNull<T> = null | T;

interface GestureResponderEvent extends NativeSyntheticEvent<NativeTouchEvent> {}

interface PanResponderGestureState {
  stateID: number;
  moveX: number;
  moveY: number;
  x0: number;
  y0: number;
  dx: number;
  dy: number;
  vx: number;
  vy: number;
  numberActiveTouches: number;
}

// React Native types used in the API
type StyleProp<T> = T | T[] | null | undefined;
type ViewStyle = Record<string, any>;
interface ViewProps {
  style?: StyleProp<ViewStyle>;
  testID?: string;
  accessible?: boolean;
  accessibilityLabel?: string;
  accessibilityHint?: string;
  accessibilityRole?: string;
  accessibilityState?: Record<string, any>;
  accessibilityValue?: Record<string, any>;
  onLayout?: (event: any) => void;
  pointerEvents?: 'none' | 'box-none' | 'box-only' | 'auto';
  removeClippedSubviews?: boolean;
  renderToHardwareTextureAndroid?: boolean;
  shouldRasterizeIOS?: boolean;
  collapsable?: boolean;
  needsOffscreenAlphaCompositing?: boolean;
  onStartShouldSetResponder?: (event: any) => boolean;
  onMoveShouldSetResponder?: (event: any) => boolean;
  onResponderGrant?: (event: any) => void;
  onResponderMove?: (event: any) => void;
  onResponderRelease?: (event: any) => void;
  onResponderTerminate?: (event: any) => void;
  onResponderTerminationRequest?: (event: any) => boolean;
  onStartShouldSetResponderCapture?: (event: any) => boolean;
  onMoveShouldSetResponderCapture?: (event: any) => boolean;
}
interface NativeSyntheticEvent<T> {
  nativeEvent: T;
  currentTarget: number;
  target: number;
  bubbles?: boolean;
  cancelable?: boolean;
  defaultPrevented?: boolean;
  eventPhase?: number;
  isTrusted?: boolean;
  preventDefault(): void;
  stopPropagation(): void;
  persist(): void;
  timeStamp: number;
  type: string;
}
interface NativeTouchEvent {
  changedTouches: Array<NativeTouchEvent>;
  identifier: string;
  locationX: number;
  locationY: number;
  pageX: number;
  pageY: number;
  target: string;
  timestamp: number;
  touches: Array<NativeTouchEvent>;
}

Default Props Values

const defaultProps = {
  animationIn: "slideInUp" as Animation | CustomAnimation,
  animationInTiming: 300,
  animationOut: "slideOutDown" as Animation | CustomAnimation,
  animationOutTiming: 300,
  avoidKeyboard: false,
  coverScreen: true,
  hasBackdrop: true,
  backdropColor: "black",
  backdropOpacity: 0.7,
  backdropTransitionInTiming: 300,
  backdropTransitionOutTiming: 300,
  customBackdrop: null,
  useNativeDriver: false,
  deviceHeight: null,
  deviceWidth: null,
  hideModalContentWhileAnimating: false,
  propagateSwipe: false,
  isVisible: false,
  panResponderThreshold: 4,
  swipeThreshold: 100,
  onModalShow: () => null,
  onModalWillShow: () => null,
  onModalHide: () => null,
  onModalWillHide: () => null,
  onBackdropPress: () => null,
  onBackButtonPress: () => null,
  scrollTo: null,
  scrollOffset: 0,
  scrollOffsetMax: 0,
  scrollHorizontal: false,
  statusBarTranslucent: false,
  supportedOrientations: ["portrait", "landscape"] as Orientation[]
};

Usage Examples

Basic Modal with Animation

import React, { useState } from "react";
import { Button, Text, View } from "react-native";
import Modal from "react-native-modal";

function AnimatedModal() {
  const [isVisible, setVisible] = useState(false);

  return (
    <View style={{ flex: 1 }}>
      <Button title="Show Modal" onPress={() => setVisible(true)} />
      
      <Modal
        isVisible={isVisible}
        animationIn="slideInUp"
        animationOut="slideOutDown"
        animationInTiming={600}
        animationOutTiming={600}
        onBackdropPress={() => setVisible(false)}>
        <View style={{ backgroundColor: "white", padding: 20 }}>
          <Text>This is a modal with custom animations!</Text>
          <Button title="Close" onPress={() => setVisible(false)} />
        </View>
      </Modal>
    </View>
  );
}

Swipeable Modal

import React, { useState } from "react";
import { Text, View } from "react-native";
import Modal from "react-native-modal";

function SwipeableModal() {
  const [isVisible, setVisible] = useState(true);

  return (
    <Modal
      isVisible={isVisible}
      swipeDirection={["up", "down"]}
      swipeThreshold={100}
      onSwipeComplete={() => setVisible(false)}
      onSwipeStart={(gestureState) => console.log("Swipe started")}
      onSwipeMove={(percentageShown) => console.log("Swipe progress:", percentageShown)}>
      <View style={{ backgroundColor: "white", padding: 20 }}>
        <Text>Swipe up or down to dismiss this modal</Text>
      </View>
    </Modal>
  );
}

Custom Backdrop Modal

import React, { useState } from "react";
import { Text, View, ImageBackground } from "react-native";
import Modal from "react-native-modal";

function CustomBackdropModal() {
  const [isVisible, setVisible] = useState(true);

  const CustomBackdrop = () => (
    <ImageBackground
      source={{ uri: "https://example.com/background.jpg" }}
      style={{ flex: 1 }}
      blurRadius={5}
    />
  );

  return (
    <Modal
      isVisible={isVisible}
      customBackdrop={<CustomBackdrop />}
      onBackdropPress={() => setVisible(false)}>
      <View style={{ backgroundColor: "white", padding: 20 }}>
        <Text>Modal with custom backdrop</Text>
      </View>
    </Modal>
  );
}

Modal with Keyboard Avoidance

import React, { useState } from "react";
import { TextInput, Button, View } from "react-native";
import Modal from "react-native-modal";

function KeyboardModal() {
  const [isVisible, setVisible] = useState(true);
  const [text, setText] = useState("");

  return (
    <Modal
      isVisible={isVisible}
      avoidKeyboard={true}
      onBackdropPress={() => setVisible(false)}>
      <View style={{ backgroundColor: "white", padding: 20 }}>
        <TextInput
          value={text}
          onChangeText={setText}
          placeholder="Type something..."
          style={{ borderWidth: 1, padding: 10, marginBottom: 10 }}
        />
        <Button title="Close" onPress={() => setVisible(false)} />
      </View>
    </Modal>
  );
}

Full Screen Modal

import React, { useState } from "react";
import { Text, Button, View } from "react-native";
import Modal from "react-native-modal";

function FullScreenModal() {
  const [isVisible, setVisible] = useState(true);

  return (
    <Modal
      isVisible={isVisible}
      style={{ margin: 0 }} // Remove default margin for full screen
      animationIn="slideInRight"
      animationOut="slideOutRight">
      <View style={{ flex: 1, backgroundColor: "white", padding: 20 }}>
        <Text>Full screen modal</Text>
        <Button title="Close" onPress={() => setVisible(false)} />
      </View>
    </Modal>
  );
}