Performant React Native Modal Component with Reanimated

Description:

React Native Reanimated Modal is an animated modal component for React Native applications.

It uses the standard React Native Modal component as its base to maintain a native look and feel across platforms.

The library integrates react-native-reanimated and react-native-gesture-handler to produce high-performance animations and interactive gestures.

Features

  • 🚀 Runs 60fps animations on the UI thread for optimal performance.
  • ðŸŽĻ Supports fade, slide, and scale animations with configurable options.
  • 👆 Offers interactive swipe-to-dismiss gestures for any direction.
  • ðŸŠķ Has minimal dependencies which contributes to a smaller application bundle size.
  • ðŸ“ą Utilizes the native React Native Modal for platform consistency.
  • 🔧 Provides a highly customizable API through various props.
  • 📚 Includes full TypeScript support for improved type safety.
  • 🔄 Integrates with React Navigation and supports multiple modal overlays.

Preview

performant-modal-reanimated

How to Use It

1. Install the package with NPM/Yarn/PNPM/BUN.

npm install react-native-reanimated-modal

2. This library requires react-native-reanimated and react-native-gesture-handler. You must install and configure these two packages in your project.

3. Wrap your application’s root component with gestureHandlerRootHOC.

import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
const App = () => {
  // Your application components
};
export default gestureHandlerRootHOC(App);

4. Import the modal and control its visibility with component state. The visible prop toggles its appearance, and the onHide callback updates the state when the modal closes.

import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { Modal } from 'react-native-reanimated-modal';
const MyComponent = () => {
  const [isModalVisible, setModalVisible] = useState(false);
  return (
    <View style={styles.container}>
      <Button title="Open Modal" onPress={() => setModalVisible(true)} />
      <Modal
        visible={isModalVisible}
        onHide={() => setModalVisible(false)}
      >
        <View style={styles.modalContent}>
          <Text>This is a modal.</Text>
          <Button title="Close" onPress={() => setModalVisible(false)} />
        </View>
      </Modal>
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  modalContent: {
    backgroundColor: 'white',
    padding: 22,
    borderRadius: 4,
    alignItems: 'center',
  },
});
export default MyComponent;

5. You can customize the modal’s behavior with the following props:

General Props

  • visible: A boolean that controls whether the modal is visible or hidden. Defaults to false.
  • children: The ReactNode content to be rendered inside the modal.
  • closable: A boolean that determines if user actions (like a backdrop press or swipe) can close the modal. Defaults to true.
  • coverScreen: A boolean. If set to true, the modal covers the entire screen without using the native Modal component, which is useful for managing multiple modal layers. Defaults to false.
  • style: Custom styles for the root container View of the modal.
  • contentContainerStyle: Custom styles applied to the animated View that wraps your children.

Configuration Props

  • animationConfig: An object or string to configure the entry and exit animations. It controls the animation type (fade, slide, scale), duration, and other specific parameters. Defaults to { animation: 'fade', duration: 300 }.
  • swipeConfig: An object to configure the swipe-to-dismiss gesture. You can enable or disable it, define swipe directions, set the swipe threshold, and customize the bounce-back animation.

Backdrop Props

  • hasBackdrop: A boolean that toggles the visibility of the backdrop. Defaults to true.
  • backdropColor: A string that sets the color of the backdrop. Defaults to 'black'.
  • backdropOpacity: A number between 0 and 1 that controls the opacity of the backdrop. Defaults to 0.7.
  • onBackdropPress: A callback function that is executed when the backdrop is pressed.
  • renderBackdrop: A function that returns a custom ReactNode to be used as the backdrop.

Event Props

  • onShow: A callback function that is executed when the modal’s “enter” animation is complete.
  • onHide: A callback function that is executed when the modal’s “exit” animation is complete.

Testing Props

  • containerTestID: A string used to set the testID for the modal’s root container View.
  • backdropTestID: A string used to set the testID for the backdrop Pressable component.
  • contentTestID: A string used to set the testID for the animated View that wraps the modal’s content.

Native Modal Props

  • hardwareAccelerated (Android)
  • navigationBarTranslucent (Android)
  • statusBarTranslucent (Android)
  • onOrientationChange (iOS)
  • supportedOrientations (iOS)

A scale animation makes the modal grow into view.

<Modal
  visible={isModalVisible}
  onHide={() => setModalVisible(false)}
  animationConfig={{
    animation: 'scale',
    duration: 500,
    scaleFactor: 0.9,
  }}
>
  {/* Modal Content */}
</Modal>

A slide animation moves the modal in from a specified direction. The direction property can define separate entry and exit animations.

<Modal
  visible={isModalVisible}
  onHide={() => setModalVisible(false)}
  animationConfig={{
    animation: 'slide',
    duration: 400,
    direction: {
      start: 'down',
      end: ['down', 'left']
    }
  }}
>  {/* Modal Content */}
</Modal>
<Modal
  visible={isModalVisible}
  onHide={() => setModalVisible(false)}
  swipeConfig={{
    enabled: true,
    directions: ['up', 'down'],
    threshold: 120,
    bounceSpringConfig: {
      stiffness: 250,
      dampingRatio: 0.6,
    },
  }}
>
  {/* Modal Content */}
</Modal>

Related Resources

  • React Native Reanimated. The animation library that powers the modal’s performance. It provides tools for creating smooth animations that run on the native UI thread.
  • React Native Gesture Handler. This library provides a more comprehensive gesture system for React Native. It is a required dependency for the modal’s swipe features.

FAQs

Q: Can I use multiple modals at the same time?
A: Yes. For handling multiple modal layers, especially with React Navigation, you can use the coverScreen={true} prop. On iOS, you can wrap your modals in the FullWindowOverlay component from react-native-screens for better layering.

Q: How do I disable the swipe-to-dismiss feature?
A: You can disable gestures by setting enabled: false inside the swipeConfig prop.

Q: Is it possible to create a full-screen modal?
A: Yes. To create a full-screen modal, you can apply flex: 1 to the contentContainerStyle prop and set hasBackdrop={false} to remove the background overlay.

Add Comment