Skip to content

doanhtu07/react-native-the-sheet

Repository files navigation

react-native-the-sheet

Reanimated v4 version Reanimated v3 version license

This is the sheet for React Native! - excluding Web

A modular bottom sheet library built on top of:

  • React Native Reanimated
  • React Native Gesture Handler
  • React Native Safe Area Context

You can DIY many aspects using the building blocks and hooks we have

android.mp4
ios.mp4

NPM packages

Installation

First, you need to determine which version of React Native Reanimated you are using

  • Choose the right version of our library based on Compatibility section below

For example, if you are using Reanimated v4, you would install v2 of our library like this:

npm install react-native-the-sheet@2.0.6

Required peer dependencies:

  • react-native-reanimated
  • react-native-gesture-handler
  • react-native-safe-area-context

react-native-universe-portal: Install if you need portal features and don't have a library of your own yet


react-native-embedded-stack-navigator: Install if you want a pure React navigator to work within the bottom sheet


While the library is stable enough for use, it is currently in a rapid experimentation phase regarding its API

  • I recommend pinning a specific version for your projects

Components

Components supported by our library:

Examples

Wrap your app with necessary providers

NOTE: Ignore portals if you don't use them

import { Stack } from 'expo-router'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import {
  SheetStackProvider,
  SheetKeyboardProvider,
} from 'react-native-the-sheet'
import { PortalHost, PortalProvider } from 'react-native-universe-portal'

export default function App() {
  return (
    <SafeAreaProvider>
      <SheetKeyboardProvider>
        <SheetStackProvider debug>
          <PortalProvider>
            <GestureHandlerRootView>
              <Stack />
              <PortalHost name="root" debug />
            </GestureHandlerRootView>
          </PortalProvider>
        </SheetStackProvider>
      </SheetKeyboardProvider>
    </SafeAreaProvider>
  )
}

Use only components you need for your use case

import { Fragment, useState } from 'react'
import { Button, StyleSheet, Text, View } from 'react-native'
import {
  Backdrop,
  BottomSheet,
  BottomSheetHandle,
  BottomSheetPresenter,
  BottomSheetView,
  SheetStackItem,
} from 'react-native-the-sheet'
import { Portal } from 'react-native-universe-portal'

export default function ExampleBottomSheetView() {
  const [isOpenA, setIsOpenA] = useState(false)

  const renderContent = () => {
    return (
      <Fragment>
        {Array.from({ length: 20 }).map((_, index) => (
          <Text key={index}>Item {index + 1}</Text>
        ))}
      </Fragment>
    )
  }

  return (
    <View style={styles.root}>
      <Text style={styles.header}>Example Bottom Sheet View</Text>

      <Button title="Open Sheet A" onPress={() => setIsOpenA(true)} />

      <Portal hostName="root">
        <SheetStackItem
          isOpen={isOpenA}
          close={() => setIsOpenA(false)}
          waitForFullyExit
          testID="sheetA"
        >
          <Backdrop />

          <BottomSheetPresenter>
            <BottomSheet>
              <BottomSheetHandle />

              <BottomSheetView>
                <Text>Sheet A</Text>
                <Button
                  title="Close Sheet A"
                  onPress={() => setIsOpenA(false)}
                />
                {renderContent()}
              </BottomSheetView>
            </BottomSheet>
          </BottomSheetPresenter>
        </SheetStackItem>
      </Portal>
    </View>
  )
}

// Styles

const styles = StyleSheet.create({
  header: {
    fontSize: 20,
    fontWeight: '500',
  },
  root: {
    flex: 1,
    gap: 8,
    padding: 16,
  },
})

Compatibility

Sheet version Reanimated version React Native Worklets version React Native version React version Expo SDK version
2.x.x (branch main) 4.x.x 0.4.x - 0.8.x 0.78 - 0.85 Depends on React Native Manages React Native
1.x.x (branch v1) 3.x.x N/A 0.63 - 0.81 Depends on React Native Manages React Native

Core dependencies

If confused, check apps/example-expo/package.json to see the versions of the core dependencies we use in our example Expo app


react-native-reanimated


react-native-worklets

  • Follows React Native Reanimated compatibility

react-native-gesture-handler

  • Follows React Native Reanimated compatibility

react-native


react

  • Follows React Native compatibility

expo

Note: You can use apps/example-expo/scripts/expo-packages-check.ts to check the packages Expo manages

  • Go to apps/example-expo
  • Run pnpm epc <expo-sdk-version> (e.g. pnpm epc 55)

react-native-safe-area-context

  • Anything is fine as long as it has:
    • SafeAreaProvider component
    • useSafeAreaInsets hook
    • useSafeAreaFrame hook

typescript

  • Anything is fine as long as it works with React Native

Roadmaps

I don't plan to support Web for a couple of reasons:

  1. Bottom sheets on web are usually not the right UX choice
  2. Web leans towards popups/modals which can be implemented much simpler with CSS and libraries like https://motion.dev

Inspiration

Thank you to all the open source projects that inspired this project:

Contributing

Resources

About

This is the sheet for React Native!

Resources

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Contributors