Bottom Sheets in React-Native.

Bottom Sheets in React-Native.

Compatible with both android and iOS.

Bottom sheets can come really handy when you are trying to show some content that demands users' attention much more than the other components in your app. Bottom sheets are also a good replacement for the traditional modal available to us from react-native as well.

Today we will be discussing not one but two packages for the bottom sheet which can be used based on our requirements. So without any further delay, let's get started!

Type 1: When your content is small [generally used to render a few buttons(2-3)]: these kinds of modals are widely used when you are uploading images or videos from the device's local storage.

P.S.: You can also use it in any other scenario as well.

Type 2: When your content is more and you would like the user to expand the content by swiping up! These types of modals can occupy up to 90% of your window.

Let’s code them !!

Prerequisites :

Begin a react native project by using the following command.

npx react-native init modalExample

image.png

Image Credits: reactnative.dev

Type 1:

  1. Let’s install the dependencies. We will be using reanimated-bottom-sheet in this case. This package has a few dependencies which we will be installing as well.

Using yarn:

yarn add reanimated-bottom-sheet react-native-reanimated@1.7.0 react-native-gesture-handler

or

Using npm:

npm install reanimated-bottom-sheet react-native-reanimated@1.7.0 react-native-gesture-handler
  1. Now move to the file where you want to implement this.

  2. Import useRef, Animated, and Bottom sheet at the top of your file.

import React, { useRef } from "react";
import BottomSheet from "reanimated-bottom-sheet";
import Animated from "react-native-reanimated";
  • Create a reference to the bottom sheet and the callbackNode.
sheetRef = useRef(null);
fall = new Animated.Value(1);
  • Now let's put the BottomSheet component on the UI.
     <BottomSheet
         ref={this.modalRef}
         snapPoints={[330, 0]}
         initialSnap={1}
         callbackNode={this.fall}
         enabledGestureInteraction={true}
         renderContent={this.showContent}
         renderHeader={this.showHeader}
      />
  • snapPoints decide the amount of real estate the component will occupy on the UI.
  • initialSnap of 1 keeps the sheet closed by default.
  • Now let's create the header and content methods to display our content.
 showHeader = () => (
    <View style={styles.panelHeader}>
      <View style={styles.modalHeader}>
        <View style={styles.panelHandle} />
        <Text style={styles.modalHeaderText}>
          Swipe down to close the modal
        </Text>
      </View>
    </View>
  );

showContent = () => (
    <>
      <View style={styles.panel}>
        <Text style={{ marginBottom: 10 }}>
          Hello World!
        </Text>
      </View>
    </>
  );
  • Put out the styles with these properties.
panelHeader: {
    backgroundColor: "#ffffff",
    paddingTop: 20,
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
    borderColor: "#ffffff",
  },
  panel: {
    padding: 20,
    backgroundColor: "#ffffff",
    paddingTop: 20,
    marginBottom: 0,
  },
  modalHeader: {
    justifyContent: "center",
    alignItems: "center",
  },
  modalHeaderText: {
    fontSize: 15,
    fontFamily: "ubuntu-semibold",
  },
  panelHandle: {
    width: 40,
    height: 8,
    borderRadius: 4,
    backgroundColor: "#00000040",
    marginBottom: 10,
  },

And that’s all. You are done.

Extras (optional) : If you want to create a background overlay, then add this function, just above the BottomSheet.

const renderShadow = () => {
    const animatedShadowOpacity = Animated.interpolate(fall, {
      inputRange: [0, 1],
      outputRange: [0.5, 0],
    });
    return (
      <Animated.View
        pointerEvents="none"
        style={[
          styles.shadowContainer,
          {
            opacity: animatedShadowOpacity,
          },
        ]}
      />
    );
  };

/* The Styles Section */
shadowContainer: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: "#292C36",
    zIndex: 10,
  },

Finally, it should be like this:

      {renderShadow()}
      <BottomSheet
        ref={this.modalRef}
        snapPoints={[330, 0]}
        initialSnap={1}
        callbackNode={this.fall}
        enabledGestureInteraction={true}
        renderContent={this.showContent}
        renderHeader={this.showHeader}
      />

Troubleshooting :

  1. If you get any errors double-check the codes in showContent(). You might have definitely forgotten to return the components from the function.

  2. If you get an error message:

TypeError: undefined is not a function

Then do either of the following :

  • Downgrade your react-native-reanimated to v1 (1.X.X).
  • Replace interpolate to interpolateNode inside renderShadow(). See docs here.

Now, let’s go to the second type.

Type 2:

  1. Let’s install the dependencies. We will be using react-native-modalize in this case. This package has a few dependencies which we will be installing as well.

Using yarn:

yarn add reanimated-bottom-sheet react-native-gesture-handler

or

Using npm:

npm install reanimated-bottom-sheet react-native-gesture-handler
  1. Now let's do the needed configuration. Move to MainActivity.java and add these lines:
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

/*  Inside MainActivity class */
@Override
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
      @Override
      protected ReactRootView createRootView() {
       return new RNGestureHandlerEnabledRootView(MainActivity.this);
      }
    };
  }
  • Now add this line to the root index.js file:
    import 'react-native-gesture-handler';
    
  • Move to the screen where you want to implement this (I am using App.js in this example):
import React, {useRef} from 'react';
import {StyleSheet, Text, View, Pressable} from 'react-native';
import {Modalize} from 'react-native-modalize';

const App = () => {
  const modalRef = useRef(null);
  return (
    <View style={styles.container}>
      <Pressable onPress={() => modalRef.current?.open()}>
        <Text>Launch Modal</Text>
      </Pressable>

      <Modalize ref={modalRef} snapPoint={180}>
          <YourModalContent />
      </Modalize>
    </View>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  button: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 15,
    borderRadius: 10,
  },
});

That's all my folks. And your bottom sheet is now ready to take your contents. I hope I could help you. Cheers! ✌🏻

If you face any issues, put them out in the comments section. I will try to help as much as I can.

Like what you read? Support me by making a small donation here. 😇