92

Is it possible to close react native modal by clicking on overlay when transparent option is true? Documentation doesn't provide anything about it. Is it possible?

acidernt
  • 2,173
  • 2
  • 19
  • 33

25 Answers25

176

If I understood correctly, you want to close the modal when the user clicks outside of it, right ?

If yes, I searched for this some time ago and the only solution that I remember was this one (which is the one that I've been using so far):

render() { 
  if (!this.state.modalVisible)
    return null
  return (
     <View>
        <Modal 
          animationType="fade"
          transparent={true}
          visible={this.state.modalVisible}
          onRequestClose={() => {this.setModalVisible(false)}}
        >
          <TouchableOpacity 
            style={styles.container} 
            activeOpacity={1} 
            onPressOut={() => {this.setModalVisible(false)}}
          >
            <ScrollView 
              directionalLockEnabled={true} 
              contentContainerStyle={styles.scrollModal}
            >
              <TouchableWithoutFeedback>
                <View style={styles.modalContainer}>
                  // Here you put the content of your modal.
                </View>
              </TouchableWithoutFeedback>
            </ScrollView>
          </TouchableOpacity>   
        </Modal> 
     </View>
  )
} 

// Then on setModalVisible(), you do everything that you need to do when closing or opening the modal.
setModalVisible(visible) {
    this.setState({
        modalVisible: visible,
    })
}

Explanation

This is basically using a TouchableOpacity in the whole screen to get when the user clicks to close the modal. The TouchableWithoutFeedback is to avoid the TouchableOpacity to work inside of the Modal.

If you have a better solution, please share here.

Gui Herzog
  • 5,327
  • 2
  • 18
  • 22
  • 3
    I solved my problem with this idea, though I see that ```TouchableOpacity``` doesn't have ```onPressOut```, and I had to use ```TouchableOpacity``` with empty action instead of ```TouchableWithoutFeedback``` – samthui7 Jun 08 '17 at 10:47
  • 1
    Will it work if modal has buttons inside. Will they be clickable? – sheriff_paul Oct 17 '18 at 18:51
  • @Goehybri, yes they will be normally clickable. All my modals have buttons inside. – Gui Herzog Oct 18 '18 at 20:36
  • It doesn't work if you want the Scroll View to be scrollable. – thodwris Mar 22 '19 at 11:05
  • @thodwris yeah the content inside scrollview become not scrollable. Did you find any workaround? – Akza May 26 '19 at 02:58
  • 1
    @Akza, it's been some time since I've written this, but I will take a look if there is any workaround. – Gui Herzog May 27 '19 at 09:44
  • 3
    where is the css for this ? – Acauã Pitta Aug 22 '20 at 14:51
  • i got the 'right' height for the ``TouchableWithoutFeedback`` with ``flexGrow: 0.65`` and ``alignContent: center`` – Acauã Pitta Aug 22 '20 at 15:59
  • 2
    To make it work `flex: 1` must not be contained in `styles.scrollModal` but it must be contained in `styles.container` – Zach Sep 26 '20 at 15:51
  • Thanks for the amazing working solution! However, does anyone also get the behavior where the modal still closes when being pressed with two fingers or more inside it? Is this actually a bug or feature? – Jarrett Jan 28 '21 at 16:01
  • Awesome! I used `Pressable` instead of `TouchableWithoutFeedback`, but the idea is the same. Thanks! – Marco Antônio Feb 10 '21 at 16:56
  • I just use to Presssables, one above and one below the modal content view . Give it the desired flex to each of them and it works perfectly fine – showtime Jun 19 '22 at 14:37
63

Another solution:

// Modal.js
import React from 'react';
import {
  TouchableWithoutFeedback,
  StyleSheet,
  Modal,
  View,
} from 'react-native';
import t from 'prop-types';


class MyModal extends React.Component {
  static propTypes = {
    children: t.node.isRequired,
    visible: t.bool.isRequired,
    dismiss: t.func.isRequired,
    transparent: t.bool,
    animationType: t.string,
  };

  static defaultProps = {
    animationType: 'none',
    transparent: true,
  };

  render() {
    const { props } = this;
    return (
      <View>
        <Modal
          visible={props.visible}
          transparent={props.transparent}
          onRequestClose={props.dismiss}
          animationType={props.animationType}
        >
          <TouchableWithoutFeedback onPress={props.dismiss}>
            <View style={styles.modalOverlay} />
          </TouchableWithoutFeedback>

          <View style={styles.modalContent}>
            {props.children}
          </View>
        </Modal>
      </View>
    );
  }
}


const styles = StyleSheet.create({
  modalContent: {
    flex: 1,
    justifyContent: 'center',
    margin: '5%',
  },
  modalOverlay: {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'rgba(0,0,0,0.5)'
  },
});


export default MyModal;

Usage example:

// SomeScreen.js
import React from 'react';
import { View, Text, Button } from 'react-native';

import Modal from './Modal';


class SomeScreen extends React.Component {
  state = {
    isModalVisible: false,
  };

  showModal = () => this.setState({ isModalVisible: true });
  hideModal = () => this.setState({ isModalVisible: false });

  render() {
    return (
      <View>
        <Button onPress={this.showModal} />
        <Modal
          visible={this.state.isModalVisible}
          dismiss={this.hideModal}
        >
          <Text>Hello, I am modal</Text>
        </Modal>
      </View>
    );
  }
}
sorrat
  • 873
  • 6
  • 11
20

Simple solution. You need one TouchableOpacity for clicking outside and another TouchableOpacity for actual modal that will do nothing onPress.

import { View, StyleSheet, TouchableOpacity, Modal} from 'react-native';

const Screen = () =>  {
  const [modalVisible, setModalVisible] = useState(false);

  return (
      <View>
          <Modal
              animationType="slide"
              transparent={true}
              visible={modalVisible}
              onRequestClose={() => setModalVisible(false) }
            >
              <TouchableOpacity style={styles.modalContainer} onPress={() => setModalVisible(false)} >
                  <TouchableOpacity style={styles.modal} activeOpacity={1} >
                      Modal Content...
                  </TouchableOpacity>
              </TouchableOpacity>
          </Modal>
      </View>
  )
}

const styles = StyleSheet.create({
  modalContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  modal: {
    width: 155,
    height: 300
  },
});

export default Screen;   

activeOpacity={1} just removes touchableOpacity fade effect

9

I tried to implement some of the suggested answers, however none worked with buttons inside modal.

I was googling around and found out that instead of using TouchableWithoutFeedback, native component called Pressable allows you to check what you click on, therefore allows you to close only when clicked on it and not it's children.

return (
   <View>
      <Modal 
        animationType="slide"
        transparent={true}
        visible={visible}
        onRequestClose={() => {
           setVisible(false)}}
      >
        <Pressable
          onPress={(event) => event.target == event.currentTarget && setVisible(false)}
          style={styles.background}
        >
          <View style={styles.modal}>
             //Content of the modal
          </View>
        </Pressable>   
      </Modal> 
   </View>
)

Found the answer here.

TomasB
  • 604
  • 5
  • 18
7

Here is my simple implementation:

<TouchableWithoutFeedback onPress={}> // Code to close your modal goes here
    <View style={styles.background}> // The view to drawn the background
            <View
                onStartShouldSetResponder={() => true}
                style={styles.container}
            > // The view to drawn your modal
            // Your content
            </View>
        </Androw>
    </View>
</TouchableWithoutFeedback>

I use TouchableWithoutFeedback since i do not want to change the background color when clicking on it. I also added onStartShouldSetResponder on the modal view to prevent closing the modal when you click inside the view.

I am also not using the Modal component because i done it using react-navigation.

Michael Wallace
  • 402
  • 3
  • 9
6

We can work it out by adding:

import { TouchableOpacity } from 'react-native';
    <TouchableOpacity onPress={()=>this.setState({modalVisibilty:false})}>
    <View style={{opacity:0, flex:1 }}/>
    </TouchableOpacity>

under the window and another one above and change the layout style to fit your screen.

Explanation:

You will make 2 big hidden buttons to catch the user touch and change the modal visibility state to false.

Mustafa Tawfig
  • 353
  • 1
  • 3
  • 9
4
<Modal isVisible={this.state.isVisible}
onBackdropPress={() => this.setState({ isVisible: false })}>
<View style={{ flex: 1 }}>
<Text>I am the modal content!</Text>
</View>
</Modal>
lostomato
  • 970
  • 8
  • 4
3

The best and easy way to do it using TouchableWithoutFeedback and Modal of react-native is

<Modal
  visible={visible}//modal visible true or false
  onRequestClose={()=>onClose(false)} // function to close modal
  transparent={true}
>
 <TouchableWithoutFeedback
   onPress={()=>onClose(false)}//outer button/view
   <View style={{flex:1, backgroundColor:'rgba(0,0,0,0.5)'}}>//for transparent view, this is outer view
    <TouchableWithoutFeedback>// outer button so any child view can be added
      <View>// this inner view
       <View>
       //your content goes here
       </View>
      </View>
    </TouchableWithoutFeedback>
   </View>
 </TouchableWithoutFeedback>
</Modal>

if you want to add flatlist better to provide height so the content won't go out of view

Pravin Ghorle
  • 606
  • 7
  • 7
2
        <Modal
            animationType="slide"
            closeOnClick={true}
            transparent={true}
            visible={this.state.modalVisible}
            >
            <TouchableOpacity onPress={() => { this.setModalVisible(!this.state.modalVisible)}} style={{flex:1, justifyContent:'center', alignItems:'center',}}>
                <View style={{flex:0.2,backgroundColor:'white', margin:20, borderRadius:20, borderWidth:2, borderColor:'gray'}}>
                    <Text style={{margin:20}}>모달 테스트</Text>
                </View>
            </TouchableOpacity>
        </Modal>

this code is my solution.

Kim HanSol
  • 23
  • 3
1

Simple solution with simple code, if you are using expo.
Here is a complete component which can you just copy and paste and get it working.

//MyModal.js

import React from 'react';
import { BlurView } from 'expo-blur';
import { View, StyleSheet, Modal, TouchableWithoutFeedback } from 'react-native';

export const MyModal = ({ children, visible, onRequestClose, onPressOverlay, }) => {
  return (
     <Modal
      visible={visible}
      transparent
      animationType='none'
      onRequestClose={onRequestClose}
     >
       <TouchableWithoutFeedback onPress={onPressOverlay}>
         <BlurView
           style={{ ...StyleSheet.absoluteFill }}
           tint='dark'
           intensity={100}
         />
       </TouchableWithoutFeedback>
       <View style={styles.container}>
         {children}
       </View>
    </Modal>
  );
};

const styles = StyleSheet.create({
  container: {
    height: '100%',
    width: '100%',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Now you can import it into your work-space and use it like this.
I'm using functional component and useState hook to show or hide the modal.

//yourScreen.js

import React, { useState } from 'react';
import { View, Button } from 'react-native';
import { MyModal } form './path/to/MyModal.js';

const YourScreen = () => {
  const [modalVisible, setModalVisible] = useState(false);
  return (
    <View style={{ flex:1 }}>
      <MyModal
        visible={modalVisible}
        onRequestClose={()=>{
          setModalVisible(false);
        }}
        onPressOverlay={()=>{
          setModalVisible(!modalVisible);
        }}
      >
        // your modal content goes here
      </MyModal>
      <Button
        title='Show Modal' 
        onPress={()=>{
          setModalVisible(!modalVisible);
        }}
      />
    </View>
  );
}

export default YourScreen;
skmak
  • 447
  • 4
  • 12
1

Here is my solution,

import React from "react";
import {Modal, StyleSheet, TouchableOpacity, TouchableWithoutFeedback, View} from "react-native";

// make sure the styles props is passed to the model and contains modalContainer, as well as the childrenContainer style objects.

export default class DismissibleModal extends React.Component {
    render() {
        return (
            <Modal
              animationType="slide"
              transparent={true}
              visible={this.props.visible}
              onRequestClose={() => {this.props.dismiss()}}>
              <TouchableOpacity
                style={Styles.modal}
                activeOpacity={1}
                onPressOut={() => {this.props.dismiss()}}>
                    <View style={[this.props.styles.modalContainer]}>
                        <TouchableWithoutFeedback>
                            <View style={[this.props.styles.childrenContainer]}>
                                {this.props.children}
                            </View>
                        </TouchableWithoutFeedback>
                    </View>
              </TouchableOpacity>
        </Modal>
        )
    }

}



const Styles = StyleSheet.create({
    modal: {
        flex: 1,
        backgroundColor: 'transparent',
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center'
    },
    modalView: {
        backgroundColor: "white",
        borderRadius: 10,
        padding: 20,
        paddingTop: 20,
        alignItems: "center",
        shadowColor: "#000",
        shadowOffset: {
            width: 0,
            height: 9,
        },
        shadowOpacity: 0.50,
        shadowRadius: 12.35,

        elevation: 19,
  },
});
Ali H. Kudeir
  • 756
  • 2
  • 9
  • 19
  • where is modalContainer css ? – Acauã Pitta Aug 22 '20 at 14:34
  • Hi, you can give it as a prop inside styles prop, as this was intended to be very general-purpose, I kept the styling for the user to modify, usually, they are background colors, width, height, and some positioning styles. – Ali H. Kudeir Aug 23 '20 at 11:34
  • i guess that is the point, the positioning style. i have this with this two touchables (opacity and withoutfeedback) example https://imgur.com/OHfyBqT - https://imgur.com/jqeVk0j but as you can see ``flexGrow:0.65`` overlap the overlay but still not 100%, you know how to adjust the ``TouchableWithoutFeedback`` to get the height/width of the image ? – Acauã Pitta Aug 23 '20 at 13:36
  • If you have given the parent component width and height, or even a flex value, you may either give it 100%, width and height and that will fill that parent's space. You may use, position absolute, and then control the location using, width, height, top, left, right and bottom. – Ali H. Kudeir Aug 23 '20 at 13:56
1

@Gui Herzog answer are quite good, but makingTouchableOpacity as a parent component, it deals with conflict when it comes touching child component.

it's not good practice having a multiple component inside of TouchableOpacity, else all component inside TouchableOpacity parent will be clickable, best way to address this problem is, make your TouchableOpacity component in absolute position, with 100% width and height in screen.

here's some example: Modal.js

export default function(props){
    const { width, height } = Dimensions.get('window');
    const hp = hp => (hp / 100) * height;
    const wp = wp => (wp / 100) * width;
    const size = size => Math.round((size / 100) * width);
    return (
        <KeyboardAvoidingView>
            <TouchableOpacity
                style={{ position: 'absolute', width: wp(100), height: hp(100) }}
                onPress={props.onTouchOutSide}
            />
            <ScrollView>
                {/*...child*/}
            </ScrollView>
        </KeyboardAvoidingView>
    )
}

You Welcome.

Marvin
  • 647
  • 7
  • 15
1

Here is the best solution for you just copy and paste. It will work definitely.

I also facing problem Here is the solution.

import React,{useState} from 'react';

import{Button,StyleSheet,View,TouchableOpacity,Modal} from 'react-native';

const App=()=>{
   const [show, setShow] = useState(false);
    return (
      <View>
        <TouchableOpacity style={{marginTop:200}}>
          <Button title='show' onPress={()=>setShow(!show)}/>
          </TouchableOpacity>   
            <Modal transparent={true} visible={show} animationType="slide">
            <TouchableOpacity activeOpacity={1} style={{backgroundColor:'#000000aa',flex:1}} onPress={()=>setShow(!show)}/>
            
            <View style={{backgroundColor:'#FFFFFF',flex: 1}}>
                <View >
                     <Button title='close' onPress={()=>setShow(!show)}/>
               </View>  
            </View>
        </Modal>
      </View>
    )};
export default App;

You Can Check Another Example Here Also:
https://snack.expo.dev/@saurabh_chavan/model-with-border-radius

Saurabh Chavan
  • 136
  • 2
  • 5
0

If you are using store solution like mobx or redux, you can simply solve with the flag on store.

Below is the parent's code,

      <Modal
        animationType="fade"
        transparent={true}
        visible={uiControlStore.dialogVisible}
        onRequestClose={() => {
          uiControlStore.dialogVisible = false;
        }}
      >
        <View
          style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(0,0,0,0.6)' }}
          onTouchStart={() => {
            if (!uiControlStore.childClicked) uiControlStore.dialogVisible = false;
            uiControlStore.childClicked= false;
          }}
        >
          <YourCustomDialog />
        </View>
      </Modal>

and below is child's code. (using mobx)

const YourCustomDialog: React.FC = observer(() => {
  const { uiControlStore } = useStores();

  return (
    <View
      style={[styles.container, styles.border]}
      onTouchStart={() => {
        uiControlStore.childClicked= true;
      }}
    >
    ...
  )
}

bychung
  • 93
  • 1
  • 4
0

I realize I'm very late to this party. But I just stumbled upon this thread and Gui Herzog's answer was exactly what I was looking for. If you don't want to add any outside dependencies that is the way to go. Thanks!

However, I wanted to include some optional negative/positive action buttons in my component and grabbed them from react-native-paper for the material style. That's when I realized react-native-paper probably have modals as well.

Here's their documentation: https://callstack.github.io/react-native-paper/modal.html
They also have a component for Dialogs https://callstack.github.io/react-native-paper/dialog.html

So I ended up with using the paper Dialog and it's well worth if if you're going to use the library throughout you app. Both Dialog and Modal handles the dismiss on click outside by default.


Here's a Dialog component created before realizing the Dialog component already exists.

I'll leave what I implemented here anyways as I think its a good template.

The component is in typescript. Make sure to have @types/react-native updated otherwise you might see some "No overload matches this call" errors.

import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {Button, Modal, Portal} from 'react-native-paper';

interface Action {
  action: () => void;
  text: string;
}

interface Props {
  closePressed: () => void;
  negativeAction?: Action;
  positiveAction?: Action;
  title?: string;
  text: string;
  visible: boolean;
}

export const Dialog: React.FC<Props> = ({
  closePressed,
  negativeAction,
  positiveAction,
  title,
  text,
  visible,
}) => {
  return (
    <Portal>
      <Modal
        visible={visible}
        onDismiss={closePressed}
        contentContainerStyle={styles.modalContainer}>
        <View style={styles.header}>
          {title && (
            <Text style={{fontWeight: 'bold', fontSize: 18, marginBottom: 10}}>
              {title}
            </Text>
          )}
          <Text style={styles.contentText}>{text}</Text>
        </View>
        <View style={styles.buttonContainer}>
          {negativeAction && (
            <Button mode="text" onPress={negativeAction.action}>
              {negativeAction.text}
            </Button>
          )}
          {positiveAction && (
            <Button mode="text" onPress={positiveAction.action}>
              {positiveAction.text}
            </Button>
          )}
        </View>
      </Modal>
    </Portal>
  );
};

const styles = StyleSheet.create({
  modalContainer: {
    borderRadius: 5,
    backgroundColor: 'white',
    padding: 10,
    margin: 20,
  },
  header: {padding: 20},
  contentText: {color: 'grey'},
  buttonContainer: {
    flexDirection: 'row',
    justifyContent: 'flex-end',
    paddingTop: 20,
  },
});
Tejpbit
  • 450
  • 1
  • 4
  • 13
0

Here is my perfectly working solution

MODAL CODE:

const ListInModal = ({ showListModal, onClose, data, onSelectItem }) => {
  return (
    <Modal animationType="none" transparent={true} visible={showListModal} onRequestClose={() => onClose(false)}>
      <TouchableOpacity onPress={() => onClose(false)} style={styles.centeredView}>
        <View style={styles.modalView}>
          <ScrollView showsVerticalScrollIndicator={false}>
            {data.map((item, index) => (
              <>
                <TouchableOpacity
                  onPress={() => {
                    onSelectItem(item);
                    onClose(false);
                  }}
                  style={{ height: 43, justifyContent: 'center' }}
                >
                  <Text style={styles.itemLabel}>{item.label}</Text>
                </TouchableOpacity>
                {index <= data.length - 2 && (
                  <View
                    style={{
                      borderBottomColor: colors.white,
                      opacity: 0.2,
                      borderWidth: 1,
                      marginHorizontal: (24 / 375) * screenWidth,
                    }}
                  />
                )}
              </>
            ))}
          </ScrollView>
        </View>
      </TouchableOpacity>
    </Modal>
  );
};

STYLING:

const styles = StyleSheet.create({
  centeredView: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#00000099',
  },
  modalView: {
    marginHorizontal: wp('5%'),
    marginVertical: hp('10%'),
    backgroundColor: colors.popupBlack,
    borderRadius: 20,
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
    elevation: 5,
  },
  itemLabel: {
    fontSize: wp('5%'),
    color: colors.white,
    paddingHorizontal: (24 / 375) * screenWidth,
  },
});

USAGE:

<ListInModal
  data={projectState?.lvApplicationTypeList}
  showListModal={showListModal}
  onClose={(bool) => setshowListModal(bool)}
  onSelectItem={(item) => onPressApplicationType(item.label)}
/>
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Ajmal Hasan
  • 885
  • 11
  • 9
0

I made it like this.

<Modal
      visible={isVisible}
      onRequestClose={() => setIsVisible(false)}
      transparent={true}
      
      >
          <Pressable style={{
              flex:1,
              backgroundColor:'transparent',
            
          }}
          onPress={()=>setIsVisible(false)}
          />
          {/* Here comes your component*/}
    </Modal>

make your component with position:absoute so Pressable can cover the whole background.

박제영
  • 101
  • 1
  • 4
0

@idiosync/react-native-modal is a hook based modal system.

https://www.npmjs.com/package/@idiosync/react-native-modal

You can add a onBackgroundPress function to the config object to achieve what you want:

useModal(
    {
      // all config params are optional apart from renderModal
      renderModal: () => <MyModal onClose={() => setModalIsVisible(false)} someProp={someProp} />,
      onBackgroundPress: () => setModalIsVisible(false),
      animationTypeIn: AnimationType.SLIDE_TOP,
    },
    modalIsVisible,
    [someProp] // dependencies array to trigger rerenders. Empty array is passed by default
  )
James Trickey
  • 1,322
  • 13
  • 21
0

2022 Answer - Using React Native Hooks

to Close a React Native Modal by clicking an Overlay is best done by using a Pressable button and TouchableOpacity

Example Below...

  • Import the Pressable and others from react-native
import React, { useState } from 'react';
import {
  Pressable,
  View,
  Text,
  TouchableOpacity,
  ScrollView,
  Modal,
  TextInput,
  StyleSheet,
} from 'react-native';
  • Then Set a State
const [modalVisible, setModalVisible] = useState(false);
  • Then Write and Design Your Modal
        <Modal
          animationType="slide"
          transparent={true}
          visible={modalVisible}
          onRequestClose={() => {
            setModalVisible(!modalVisible);
          }}
        >
          <TouchableOpacity
            onPress={() => setModalVisible(false)}
            style={styles.modalContainerStyle}
          >
            <Pressable
              onPress={() => setModalVisible(true)}
              style={styles.modalContent}
            >
              <ScrollView>
                <View>
                  <Text style={styles.modalTitle}>TITLE HERE</Text>

                  <Text style={styles.modalText}>
                    OTHER SMALLER TEXT HERE
                  </Text>

                  <Text style={styles.modalFormText}>AN INPUT</Text>
                  <TextInput
                    style={styles.modalInput}
                    value={inputValue}
                    onChangeText={(inputValue) => handleInputValue(inputValue)}
                    placeholder={'example@email.com'}
                  />

                  <View style={styles.btnView}>
                    <TouchableOpacity
                      onPress={() => setModalVisible(!modalVisible)}
                      underlayColor="white"
                    >
                      <View style={styles.buttonProceed}>
                        <Text style={styles.buttonText}>NEXT</Text>
                      </View>
                    </TouchableOpacity>
                  </View>
                </View>
              </ScrollView>
            </Pressable>
          </TouchableOpacity>
        </Modal>

  • Now To Open Your Modal (Using a Text Button)
<Pressable onPress={() => setModalVisible(!modalVisible)}>
  <Text style={styles.openModal}>Open Modal</Text>
</Pressable>
  • Finally Style Your Modal
modalContainerStyle: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'flex-end',
    backgroundColor: 'rgba(0, 0, 0, 0.3)',
  },
  modalContent: {
    borderTopLeftRadius: 27,
    borderTopRightRadius: 27,
    width: '100%',
    height: '60%',
    backgroundColor: '#FFFFFF',
    paddingLeft: 33,
    paddingRight: 33,
    overflow: 'hidden',
  },
  modalTitle: {
    marginTop: 43,
    marginBottom: 14,
    fontSize: 19,
    lineHeight: 21,
    color: 'black',
    fontFamily: 'GraphikBold',
  },
  modalText: {
    fontSize: 15,
    lineHeight: 25,
    marginBottom: 38,
    color: 'black',
    fontFamily: 'GraphikRegular',
  },
  modalFormText: {
    marginBottom: 10,
    fontSize: 15,
    color: 'black',
    fontFamily: 'GraphikMedium',
  },
  modalInput: {
    marginBottom: 99,
    height: 44,
    paddingLeft: 17,
    paddingRight: 17,
    fontSize: 16,
    borderRadius: 10,
    marginBottom: 20,
    borderWidth: 1,
    fontFamily: 'GraphikRegular',
    borderColor: 'rgba(118, 118, 118, 0.17)',
  },
  openModal: {
    marginRight: 5,
    textAlign: 'right',
    color: '#ED2125',
    fontFamily: 'GraphikMedium',
  },
  • Sorry, but this answer has way too many unnecessary details which are not relevant for the OPs question. It's really hard to find the relevant code in your example. In addition to that, TouchableOpacity is a bad idea as clicking outside the content shouldn't have any visual feedback. Please remove the bold headline with increased font size. – Pawel Aug 10 '22 at 17:39
0

recently faced the issue, tried solving it using a two touchable opacity, you can also turn off the closing on tapping anywhere behaviour by passing the isDismissable value to false.

import { View, Text, Modal, StyleSheet, TouchableOpacity } from 'react-native';
import React from 'react';

type PropType = {
  open: boolean;
  onClose: () => void;
  isDismissable?: boolean;
  children: JSX.Element | JSX.Element[];
};

const styles = StyleSheet.create({
  modalRootContainer: {
    flexGrow: 1,
  },
  outerContainer: {
    height: '100%',
  },
});

const BottomModal = ({
  open,
  onClose,
  isDismissable = true,
  children,
}: PropType) => {
  return (
    <Modal
      visible={open}
      transparent
      onRequestClose={onClose}
      animationType='slide'
    >
      <TouchableOpacity
        style={styles.outerContainer}
        activeOpacity={1}
        onPress={() => {
          if (isDismissable) onClose();
        }}
      >
        <View style={styles.modalRootContainer}>
          <TouchableOpacity activeOpacity={1}>{children}</TouchableOpacity>
        </View>
      </TouchableOpacity>
    </Modal>
  );
};

export default BottomModal;
fahad991
  • 452
  • 3
  • 8
0

*it's a very simple and effective solution I just applied it to my app and its works as I wanted. just wrap your child component into TouchableOpacity

EXAMPLE:

 <Modal
        animationType="slide"
        transparent={true}
        visible={IsCamaraShow}
        onRequestClose={() => {
          setIsCamaraShow(!IsCamaraShow);
        }}>
        <View style={Styles.centeredView1}>
        <TouchableOpacity style={Styles.centeredView1} 
        onPress={()=> setIsCamaraShow(!IsCamaraShow)}
        activeOpacity={1}
        >
          <View style={Styles.modalView1}>
           
            {cosnole.log( 'rest of your code') }
  
          </View>
        </TouchableOpacity>
        </View>
      </Modal>
0

Would recommend the following which worked well for me:

  • Use two <Pressable> components inside the modal
  • First one with opacity-1 and flex-1, no content and onPress that closes the modal
  • Second one with style according to how you want the modal content to show and text content inside

<Modal 
  animationType="slide" 
  transparent 
  visible={isModalVisible} 
  onRequestClose={() => setIsModalVisible(false)
>
  <Pressable 
    onPress={() => setIsModalVisible(false)}
    style={{flex: 1, opacity: 0}}
  />
  <Pressable
    style{{height: '25%', width: '100%', position: 'absolute', bottom: 0, justify-content: 'center', align-items: 'center'}}
  >
    <Text>Content of modal</Text>
  </Pressable>
</Modal>
0

You can install react-native-modal it's way more simpler and it has a property onBackdropPress just for this case

PS: it even has some animations which makes it look way better than the normal modal

Sherif Samir
  • 259
  • 3
  • 5
-1

I have solved this in react native 0.64 by given below code

 <Modal  
     isVisible={ModalVisible}  

      onBackdropPress={()=>{setModalVisible(false)}}
       >
      .
      .
      . 
  </Modal>
-4

Hi I am using a lightweight popup react-native-easypopup it also closing itself when you tap out of popup.

npm i react-native-easypopup

yowovogu
  • 5
  • 6