React Navigation half modal with backdrop close

React Navigation half modal with backdrop close

One of the most used components in front-end development is modals. It has a lot of use cases, for example, you can use modals as a select component for filtering lists or alert dialog, etc.

React Navigation offers really good API to create modals. In this tutorial, we will learn how to make a half-modal with backdrop close functionality.

First of all, We need to create our root navigation and a simple screen to open a modal over it.

In the code above, you can see we have another group for the modal. Group API comes with React Navigation 6. it's useful to change the behavior of the stack without creating another one. here we used   transparentModal for presentation which means we can give style for the modal content. and headerShown is false because we don't need to see the header in this modal screen.

import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from 'react-native-paper';

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import ModalScreen from './modal';
function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text style={{ fontSize: 30 }}>This is the home screen!</Text>
      <Button
        style={{ marginTop: 40 }}
        mode="contained"
        onPress={() => navigation.navigate('MyModal')}>
        Open Modal
      </Button>
    </View>
  );
}
const RootStack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <RootStack.Navigator>
        <RootStack.Group>
          <RootStack.Screen name="Home" component={HomeScreen} />
        </RootStack.Group>
        <RootStack.Group
          screenOptions={{
            presentation: 'transparentModal',
            headerShown: false,
          }}>
          <RootStack.Screen name="MyModal" component={ModalScreen} />
        </RootStack.Group>
      </RootStack.Navigator>
    </NavigationContainer>
  );
}

export default App;

In the modal screen, we actually don't have any background color for the main view. but in the child component, there is Pressable the component that fills the entire screen. and the actual content is inside  Animated.View and animates from the bottom to half of the screen.

import {
  Animated,
  View,
  Text,
  Pressable,
  StyleSheet,
  useWindowDimensions,
} from 'react-native';
import { useCardAnimation } from '@react-navigation/stack';
import { Button } from 'react-native-paper';

const styles = StyleSheet.create({
  viewAnimated: {
    width: '100%',
  },
  viewContainer: {
    flex: 1,
    padding: 10,
    backgroundColor: '#E5E5E5',
    borderRadius: 20,
  },
});
function ModalScreen({ navigation }) {
  const { height } = useWindowDimensions();
  const { current } = useCardAnimation();

  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
      }}>
      <Pressable
        style={[
          StyleSheet.absoluteFill,
          { backgroundColor: 'rgba(0, 0, 0, 0.5)' },
        ]}
        onPress={navigation.goBack}
      />
      <Animated.View
        style={[
          {
            height: height,
            transform: [
              {
                translateY: current.progress.interpolate({
                  inputRange: [0, 1],
                  outputRange: [height, height * 0.5],
                  extrapolate: 'clamp',
                }),
              },
            ],
          },
          styles.viewAnimated,
        ]}>
        <View style={styles.viewContainer}>
          <Text>
            Lorem Ipsum is simply dummy text of the printing and typesetting
            industry. Lorem Ipsum has been the industry's standard dummy text
            ever since the 1500s, when an unknown printer took a galley of type
            and scrambled it to make a type specimen book. It has survived not
            only five centuries, but also the leap into electronic typesetting,
            remaining essentially unchanged. It was popularised in the 1960s
            with the release of Letraset sheets containing Lorem Ipsum passages,
            and more recently with desktop publishing software like Aldus
            PageMaker including versions of Lorem Ipsum.
          </Text>
          <Button
            style={{ marginTop: 40 }}
            mode="contained"
            onPress={navigation.goBack}>
            Close Modal
          </Button>
        </View>
      </Animated.View>
    </View>
  );
}
export default ModalScreen;
React Navigation Half modal - Snack
Try this project on your phone! Use Expo’s online editor to make changes and save your own copy.