How to Create Bottom Sheet Using React Native Modal

Introduction of Bottom Sheet –

In this tutorial, we are going to discuss an example of a Bottom Sheet creation in React Native, which is titled “How to Create Bottom Sheet Using React Native Modal”.

And the good part of this tutorial is, for creating a Bottom Sheet we will not use any third-party library.

Excited to know? how we developed this, so let’s start.

We are going to use the Modal component provided by react native and apply custom CSS to this for achieving the result.

Bottom Sheet Output Example –

About Bottom Sheet – 

Bottom Sheet was first introduced in material design for Android and it became very popular every developer use it in his project. And it also uses by Different people and in different ways.

Here is a simple example that we see in day-to-day life when you share something when you block and report some, and also when you want to see view more options.

Break down the blog steps –

Here we break down the blogs in steps, so it is easy to you to follow the blog.

  • Create a fresh React Native App
  • Run the app
  • Import the component
  • Design the modal
  • Apply the CSS

So let’s start following the steps.

Step 1 – App creation for Bottom Sheet Implementation

Firstly we need to create a React Native app for implementing Bottom Sheet.

react-native init bottomSheetProject

Step 2 – Run the app

Now we run the app so we check everything is working fine.

react-native run-android

Step 3 – Import the API for Bottom Sheet

React Native provides a Modal component.

You can use Modal inside a ScrollView or within render() for Bottom Sheet look functionality.

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

Step 4 – Creating View More Icon

Here we create a view more icon when you click on that icon modal bottom sheet is opened.

 <View style={{flex: 1, backgroundColor: 'black'}}>
        <StatusBar
          hidden={false}
          translucent={false}
          barStyle="light-content"
          networkActivityIndicatorVisible={true}
          backgroundColor={'black'}
        />
        <SafeAreaView style={{backgroundColor: 'black'} />      
          <TouchableOpacity
              onPress={() => {
                this.setState({mediamodal: true});
              }}
              style={{width: '10%'>
// i am using image for showing 3 - dots that is stored in my local folder, you can use vector icon or image
              <Image
                style={{
                  width: 100,
                  height: 100,
                  resizeMode: 'contain',
                  alignSelf: 'center',
                }}
                source={localimag.dots}></Image>
            </TouchableOpacity>
      </SafeAreaView> </View>

The output of this section looks like –

bottom sheet open

Now when we click on this icon we set the state, so it shows the bottom sheet on click.

Step 5 – State Declaration For Popup Hide Show

Now we need to create a state, which we set by default false and when the user clicks on this is open the popup

 constructor(props) {
    super(props);
    this.state = {
      mediamodal: false,
    };
  }
//mediamodal is our state for setting popup open/close

Step 6 – Modal Implementation

Here we implement the modal within our App.js file you can integrate it anywhere or any file where you want to implement this functionality.

 {/* --------------- Modal for report user option---------- */}
        <Modal
          animationType="slide"
          transparent={true}
          visible={this.state.mediamodal}
          onRequestClose={() => {
            this.setState({mediamodal: false});
          }}>
          <TouchableOpacity
            onPress={() => {
              this.setState({mediamodal: false});
            }}
            style={styles.modalTextViewBG}>
            <View style={styles.mainModalView}>
              <View style={styles.subModalView}>
                <TouchableOpacity
                  onPress={() => {
                    alert('popup opened')
                  }}
                  activeOpacity={0.7}
                  style={styles.modalTextView}>
                  <Text style={styles.reportUserText}>
                    {'Report User'}
                  </Text>
                </TouchableOpacity>
              </View>
              <TouchableOpacity
                style={styles.modalBtnView}
                onPress={() => {
                  this.setState({mediamodal: false});
                }}>
                <Text style={styles.modalBtnText}>
                  {'Cancel'}
                </Text>
              </TouchableOpacity>
            </View>
          </TouchableOpacity>
        </Modal>

Step 7 – Let’s add Styling

Now we are going to add the CSS, which is the most important part of this blog, so we achieve our result.

// These are user defined styles
const styles = StyleSheet.create({
  mainModalView: {
    width: '90%',
    position: 'absolute',
    bottom: (mobileW * 3) / 100,
    alignSelf: 'center',
    alignItems: 'center',
  },
  subModalView: {
    width: '100%',
    backgroundColor: '#FFFFFF',
    alignSelf: 'center',
    borderRadius: (mobileW * 5) / 100,
  },
  modalTextView: {
    width: '100%',
    borderBottomColor: '#e7e7e7',
    alignSelf: 'center',
    paddingVertical: (mobileW * 4) / 100,
  },
  reportUserText: {
    width: '100%',
    textAlign: 'center',
    fontSize: (mobileW * 4) / 100,
    color: 'black',
  },
  modalBtnView: {
    width: '100%',
    backgroundColor: '#FFFFFF',
    paddingVertical: (mobileW * 5) / 100,
    alignSelf: 'center',
    borderRadius: (mobileW * 2.5) / 100,
    marginTop: (mobileW * 3) / 100,
  },
  modalBtnText: {
    width: '100%',
    textAlign: 'center',
    color: 'black',
    fontSize: (mobileW * 4) / 100,
  },
  modalTextViewBG: {flex: 1, backgroundColor: '#000000aa'},

});

Step 7 – Complete Code

Here I am posting the complete file code just for your good understanding and you get the exact result.

Note: – Use your own color, images, icon and button

import React, {Component} from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Image,
  SafeAreaView,
  Dimensions,
  StatusBar,
  ImageBackground,
  Modal,
  StyleSheet,
} from 'react-native';

import FlatButton from '../components/FlatButton';

const mobileH = Math.round(Dimensions.get('window').height);
const mobileW = Math.round(Dimensions.get('window').width);

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mediamodal: false,
    };
  }

  render() {
    return (
      <View style={{flex: 1, backgroundColor: 'black'}}>
        <StatusBar
          hidden={false}
          translucent={false}
          barStyle="light-content"
          networkActivityIndicatorVisible={true}
          backgroundColor={'black'}
        />
        <SafeAreaView style={{backgroundColor: Colors.BlackColor}} />
        {/* --------------- Modal for report user option---------- */}
        <Modal
          animationType="slide"
          transparent={true}
          visible={this.state.mediamodal}
          onRequestClose={() => {
            this.setState({mediamodal: false});
          }}>
          <TouchableOpacity
            onPress={() => {
              this.setState({mediamodal: false});
            }}
            style={styles.modalTextViewBG}>
            <View style={styles.mainModalView}>
              <View style={styles.subModalView}>
                <TouchableOpacity
                  onPress={() => {
                    this.setState({mediamodal: false});
                  }}
                  activeOpacity={0.7}
                  style={styles.modalTextView}>
                  <Text style={styles.reportUserText}>{'Report User'}</Text>
                </TouchableOpacity>
              </View>
              <TouchableOpacity
                style={styles.modalBtnView}
                onPress={() => {
                  this.setState({mediamodal: false});
                }}>
                <Text style={styles.modalBtnText}>{'Cancel'}</Text>
              </TouchableOpacity>
            </View>
          </TouchableOpacity>
        </Modal>

        <ImageBackground style={{flex: 1}}>
          <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
            <TouchableOpacity
              onPress={() => {
                this.props.navigation.goBack();
              }}
              style={{width: '10%', marginTop: (mobileW * 2) / 100}}>
              <Image
                style={{
                  width: (mobileW * 9) / 100,
                  height: (mobileW * 9) / 100,
                  resizeMode: 'contain',
                  alignSelf: 'center',
                }}
                source={localimag.crossicon}></Image>
            </TouchableOpacity>

            <TouchableOpacity
              onPress={() => {
                this.setState({mediamodal: true});
              }}
              style={{width: '10%', marginTop: (mobileW * 2) / 100}}>
              <Image
                style={{
                  width: (mobileW * 9) / 100,
                  height: (mobileW * 9) / 100,
                  resizeMode: 'contain',
                  alignSelf: 'center',
                }}
                source={localimag.dots}></Image>
            </TouchableOpacity>
          </View>
          <View
            style={{
              marginTop: (mobileH * 15) / 100,
              alignSelf: 'center',
            }}>
            <View
              style={{
                height: (mobileW * 26.2) / 100,
                width: (mobileW * 26.2) / 100,
                borderRadius: (mobileW * 50) / 100,
                borderWidth: (mobileW * 1.2) / 100,
                borderColor: Colors.YellowColor,
                alignSelf: 'center',
              }}>
              <Image
                style={{
                  borderRadius: (mobileW * 50) / 100,
                  borderWidth: (mobileW * 1.5) / 100,
                  borderColor: Colors.WhiteColor,
                  height: (mobileW * 23.9) / 100,
                  width: (mobileW * 23.9) / 100,
                  borderRadius: (mobileW * 50) / 100,
                }}
                source={localimag.erroricon}></Image>
            </View>
          </View>

          <View
            style={{
              width: '90%',
              alignSelf: 'center',
              marginTop: (mobileH * 2) / 100,
            }}>
            <Text
              style={{
                color: Colors.WhiteColor,
                alignSelf: 'center',
                fontFamily: Font.FontMedium,
                fontSize: (mobileW * 5) / 100,
              }}>
              {'Test User' + ', ' + '28'}
            </Text>
            <View style={{flexDirection: 'row', alignSelf: 'center'}}>
              <Image
                style={{
                  height: (mobileW * 4) / 100,
                  width: (mobileW * 4) / 100,
                  alignSelf: 'center',
                }}
                source={localimag.erroricon}></Image>
              <Text
                style={{
                  marginLeft: (mobileW * 1) / 100,
                  color: Colors.WhiteColor,
                  alignSelf: 'center',
                  fontFamily: Font.FontMedium,
                  fontSize: (mobileW * 4) / 100,
                }}>
                {'India'}
              </Text>
            </View>
          </View>
          <View
            View
            style={{
              position: 'absolute',
              bottom: 5,
              alignSelf: 'center',
              width: '90%',
            }}>
            <FlatButton
              onPress={() => {
                alert('video call');
              }}
              buttonTitle={'Start Video call'}
            />
            <TouchableOpacity
              activeOpacity={0.7}
              style={{width: '40%', alignSelf: 'center'}}
              onPress={() => {
                alert('Skip');
              }}>
              <Text
                style={{
                  color: Colors.WhiteColor,
                  alignSelf: 'center',
                  marginTop: (mobileW * 2) / 100,
                  fontFamily: Font.FontMedium,
                  fontSize: (mobileW * 4.5) / 100,
                }}>
                {'Skip'}
              </Text>
            </TouchableOpacity>
          </View>
        </ImageBackground>
      </View>
    );
  }
}
export default StartVideo;

// These are user defined styles
const styles = StyleSheet.create({
  mainModalView: {
    width: '90%',
    position: 'absolute',
    bottom: (mobileW * 3) / 100,
    alignSelf: 'center',
    alignItems: 'center',
  },
  subModalView: {
    width: '100%',
    backgroundColor: '#FFFFFF',
    alignSelf: 'center',
    borderRadius: (mobileW * 5) / 100,
  },
  modalTextView: {
    width: '100%',
    borderBottomColor: '#e7e7e7',
    // borderBottomWidth: 1,
    alignSelf: 'center',
    paddingVertical: (mobileW * 4) / 100,
  },
  reportUserText: {
    width: '100%',
    textAlign: 'center',
    fontFamily: Font.FontMedium,
    fontSize: (mobileW * 4) / 100,
    color: Colors.mediatextcolor,
  },
  modalBtnView: {
    width: '100%',
    backgroundColor: '#FFFFFF',
    paddingVertical: (mobileW * 5) / 100,
    alignSelf: 'center',
    borderRadius: (mobileW * 2.5) / 100,
    marginTop: (mobileW * 3) / 100,
  },
  modalBtnText: {
    width: '100%',
    textAlign: 'center',
    color: Colors.BlackColor,
    fontSize: (mobileW * 4) / 100,
    fontFamily: Font.semibold_font,
  },
  modalTextViewBG: {flex: 1, backgroundColor: '#000000aa'},
});

So we completed the react-native  Bottom Sheet With Modal which is “How to Create Bottom Sheet Using React Native Modal

Here You find my next post here.

My website for B2B – https://www.beparr.com/

My Startup for B2B Retailers – https://play.google.com/store/apps/details?id=com.beparr.buyer

In conclusion, If have any queries or issues, please feel free to ask.

Happy Coding Guys.

Final Output For iOS –

bottom sheet output with react native modal

Related Post