React Native Modals in 2025

Explore the different approaches to implementing modals in React Native for 2025. From built-in solutions to advanced implementations, learn which modal strategy best suits your cross-platform development needs.

Monday March 24th 2025 | 10 min read

React Native Modals in 2025 blog post header image

At Add Jam we've been sharing out knowledge and experience with React Native in blog posts covering a range of topics such as adding Live Activities to a React Native app and handling Internationalisation. Continuing this theme, we've put together a comprehensive guide to 'modals' in React Native.

What are modals?

Often in software products you want to display content over the top of the current screen, you don't want to navigate to a new screen or just add content to the current screen. For example, you want to display a confirmation dialog or have a soft prompt to ask the user for notification permission or maybe you want to show some additional information. To do this on web, mobile and desktop we turn to modals.

Modals are a great way to handle these types of interactions and are a core part of the user experience in many apps.

When implementing a React Native app how do you approach modals? Well it isn't just a one-size-fits-all deal. Sometimes you might just need a simple pop-up, while others require gesture backed swipe-able sheets that feel like they're part of the core iOS or Android experience. As a team with almost 10 years experience shipping React Native to production we've collated the different approaches to implementing modals in React Native for 2025.

The built-in React Native Modal component

When you're looking for a straightforward way to display content overlay, React Native's built-in Modal component might be just what you need. It's baked into the React Native core and is a great starting point for simple use cases.

We've used this approach countless times for simple confirmation dialogs, quick settings panels, and image previews. It's particularly great when you need something up and running quickly without the overhead of additional dependencies.

Pros:

  • Built into React Native
  • Zero additional dependencies
  • Lightweight and performant
  • Perfect for simple use cases

Cons:

  • Limited styling options
  • Basic animation capabilities
  • Less flexible for complex interactions
  • Can be challenging to achieve platform-specific behaviours

Here's how you might implement a basic modal component that wraps the built-in Modal component. This approach allows you to create a consistent modal component that can be reused across your app:

interface SimpleModalProps {
  visible: boolean
  onClose: () => void
  title: string
  content: string
}

const SimpleModal: React.FC<SimpleModalProps> = ({ 
  visible, 
  onClose, 
  title, 
  content 
}) => {
  return (
    <Modal
      visible={visible}
      animationType="slide"
      transparent={true}
      onRequestClose={onClose}
    >
      <View style={styles.centeredView}>
        <View style={styles.modalView}>
          <Text style={styles.modalTitle}>{title}</Text>
          <Text style={styles.modalContent}>{content}</Text>
          <Pressable 
            style={styles.button}
            onPress={onClose}
          >
            <Text style={styles.buttonText}>Close</Text>
          </Pressable>
        </View>
      </View>
    </Modal>
  )
}

const styles = StyleSheet.create({
  centeredView: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.5)'
  },
  modalView: {
    margin: 20,
    backgroundColor: 'white',
    borderRadius: 20,
    padding: 35,
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 2
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5
  }
})

NB there are some platform specific props you can use to customise the modal for the platform you are building for. For example, on iOS you can use the presentationStyle prop to change the modal appears.

Bottom Sheet Modal

If you've ever used Apple Maps or a food delivery app, you've probably encountered the 'bottom sheet' UI paradigm which as far as we're concerned is another type of modal. The 'bottom sheet' is one of those panels that slide up from the bottom of the screen and can be dragged/snapped to different positions. They've become incredibly popular because they feel natural and intuitive then because they're used across stock apps on iOS and Android (like the native map apps) they can help make your app feel more part of the phone's operating system itself.

Bottom sheets are particularly brilliant for apps that need to show contextual information while keeping the main content visible (like mapping apps). Think of a map where you want to show location details, or a music player where you want to show the current playlist without completely hiding the player controls.

Our implementation of bottom sheets is using the react-native-bottom-sheet library which is a popular and well maintained library.

Pros:

  • Native feeling interactions
  • Customisable snap points
  • Gesture-based interactions
  • Perfect for map-based applications

Cons:

  • Additional dependencies required
  • Needs react-native-reanimated and react-native-gesture-handler dependencies too
  • Slightly more complex setup

Here's a TypeScript example using the popular bottom sheet library:

interface LocationData {
  name: string
  address: string
  coordinates: {
    latitude: number
    longitude: number
  }
}

interface MapBottomSheetProps {
  data: LocationData
  onLocationSelect: (location: LocationData) => void
}

const MapBottomSheet: React.FC<MapBottomSheetProps> = ({ 
  data, 
  onLocationSelect 
}) => {
  const bottomSheetRef = useRef<BottomSheet>(null)
  const snapPoints = useMemo(() => ['25%', '50%', '75%'], [])

  const handleSheetChanges = useCallback((index: number) => {
    console.log('handleSheetChanges', index)
  }, [])

  return (
    <BottomSheet
      ref={bottomSheetRef}
      index={1}
      snapPoints={snapPoints}
      onChange={handleSheetChanges}
      enablePanDownToClose
    >
      <View style={styles.contentContainer}>
        <Text style={styles.locationTitle}>{data.name}</Text>
        <Text style={styles.locationAddress}>{data.address}</Text>
        <Pressable 
          style={styles.selectButton}
          onPress={() => onLocationSelect(data)}
        >
          <Text style={styles.buttonText}>Select Location</Text>
        </Pressable>
      </View>
    </BottomSheet>
  )
}

As with any dependency, you'll need to weigh up the cost of adding a new dependency (in regards to bundle size, maintenance, etc) with the benefits it may bring to your app.

React Navigation Modal Screens

Navigation modals are a bit different from your typical popup modals. They're perfect when you need to present an entirely new context to your user, like a settings page or a photo editing screen. What's great about React Navigation's approach is that it handles all the platform-specific animations and gestures out of the box.

In likelyhood you'll already be using React Navigation in your app so this is a great approach of adding 'native feeling' modals to your app without adding any additional dependencies.

Pros:

  • Seamless integration with React Navigation
  • Native platform animations
  • Built-in back gesture support
  • Consistent with platform conventions

Cons:

  • Requires React Navigation setup
  • More suitable for full-screen modals
  • May be overkill for simple popup needs

Here's how you'd set up a modal screen with. It's a new screen that you'll navigate to, so it's a bit more work to set up and perhaps against the grain of a simple to show info screen when compared to our other options but it's a great approach for full-screen modals:

type RootStackParamList = {
  Home: undefined
  ProductModal: { productId: string }
}

const Stack = createStackNavigator<RootStackParamList>()

interface ProductModalScreenProps {
  route: RouteProp<RootStackParamList, 'ProductModal'>
  navigation: StackNavigationProp<RootStackParamList, 'ProductModal'>
}

const ProductModalScreen: React.FC<ProductModalScreenProps> = ({ 
  route, 
  navigation 
}) => {
  const { title } = route.params

  return (
    <View style={styles.modalContainer}>
      <Pressable 
        style={styles.closeButton}
        onPress={() => navigation.goBack()}
      >
        <Text>Close</Text>
      </Pressable>
      <Text>{title}</Text>
    </View>
  )
}

function App() {
  return (
    <Stack.Navigator>
      <Stack.Group>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Group>
      <Stack.Group screenOptions={{ presentation: 'modal' }}>
        <Stack.Screen 
          name="ProductModal" 
          component={ProductModalScreen} 
        />
      </Stack.Group>
    </Stack.Navigator>
  )
}

Other approaches to consider

THe above examples are how Add Jam has implemented modals in production React Native apps that are used by thousands of users. However, there are other approaches to consider.

Expo Router Modals: The File-System Approach

Expo Router has brought a fresh perspective to handling modals in React Native. If you're using Expo (and many teams are these days), the router allows file-based routing which has support for modals. It's as simple as creating a file in the right place - no complex navigation setup required.

We've not used this approach in a production app yet but it's worth considering if you're using Expo Router. It's worth noting Expo Router is built on top of React Navigation which is widely used and battle tested.

React Native Portal

Sometimes you need to render modals from deeply nested components without prop drilling or complex state management. That's where portals come in handy. They're like a teleporter for your UI components, letting you render content anywhere in your app's component tree.

We've not used this approach ourselves but it's worth considering if you need to render modals from deeply nested components.

Choosing the right approach

As with many things there's no singular 'right' way to approach Modals in React Native. You need to weigh up the user experience, accessibility, performance, and the complexity of the approach among other things. But that isn't useful advice is it? So here's stab at some general guidelines for choosing your approach to modals:

For really simple information display

Go with the built-in Modal when:

  • You're showing simple alerts or confirmations
  • Your modal doesn't need complex animations
  • You want to keep dependencies minimal

For interactive experiences

Choose Bottom Sheet when:

  • Users need to peek at content while maintaining context
  • Your app has a map or spatial interface
  • You want that native iOS/Android feel

For the most 'native' feeling modals

Use React Navigation modals when:

  • You need full-screen forms or workflows
  • Your modal has its own navigation stack
  • You want platform-specific transitions out of the box

Top tips for implementing modals

  • Performance First: Start with performance in mind - it's easier than optimising later.
  • Accessibility Matters: however you implement your modal make sure to your modal is accessible to everyone. Test it out on device with VoiceOver and other accessibility tools.
  • Handle Gestures Properly: run the modal on device, are the gestures working as expected and intuitive?
  • Balance the cost of adding a new dependency with the benefits it may bring to your app. Dependencies can add to the bundle size and can stop being maintained.
  • Run on device, not in the simulator. This is not just for testing the gestures or accessibility, your modal may look and behave differently on devices and consider all the different screen sizes and orientations.
  • Platform Differences - iOS and Android are different, make sure to test on both and consider the platform specific behaviours.

Apply the right modal for the right job

Modals might seem simple on the surface, but choosing and implementing modals in your app will have a profound impact on the user experience.

At Add Jam, we've implemented all these approaches across various projects, from fun tourist information apps to complex EV Charging solutions. We understand that each project has unique needs, and we're here to help you choose and implement the right modal strategy for your specific case.

Need help making sense of all these options? Want to ensure you're building your React Native product the right way? Get in touch with our team - we'd love to help you create an exceptional mobile experience.


Looking for expert React Native developers? Add Jam specialises in creating robust, scalable mobile applications using React Native. From initial concept to deployment and beyond, we're here to help. Contact us to discuss your project.

For more insights into React Native development, check out other React Native blog posts such as Using Live Activities in a React Native App.

Michael Hayes's avatar

Michael Hayes

Co-founder

Recent case studies

Here's a look at some of products we've brought to market recently

Educational Intelligence: Money Matters

Educational Intelligence: Money Matters

How Add Jam partnered with Educational Intelligence to create Money Matters, a digital platform addressing the UK's financial literacy crisis where 12.9 million adults struggle with money management.

Great Glasgow Coffee Run

Great Glasgow Coffee Run

Celebrating Glasgow's vibrant coffee culture and running community through an interactive digital experience that maps out the perfect coffee-fuelled running route through the city.

One Walk A Day

One Walk A Day

During lockdown we rapidly prototyped a health and wellbeing app using React Native then expanded on the concept and redeveloped using SwiftUI

We take products from an idea to revenue

Add Jam is your plug in team of web and mobile developers, designers and product managers. We work with you to create, ship and scale digital products that people use and love.

Hello, let's chat 👋