Bottom Sheet

A bottom sheet helps people perform a scoped task that's closely related to their current context.

Installation

Before copy/pasting, add the following dependencies to your project:

Next, wrap your root component with a GestureHandlerRootView (with a style of flex: 1) and a BottomSheetModalProvider.

~/app/_layout.tsx
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

export default function Layout({ children }) {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <BottomSheetModalProvider>
        {children}
      </BottomSheetModalProvider>
    </GestureHandlerRootView>
  );
}
~/components/nativewindui/Sheet.tsx
import {
  BottomSheetBackdrop,
  BottomSheetBackdropProps,
  BottomSheetModal,
} from '@gorhom/bottom-sheet';
import * as React from 'react';

import { useColorScheme } from '~/lib/useColorScheme';

const Sheet = React.forwardRef<
  BottomSheetModal,
  React.ComponentPropsWithoutRef<typeof BottomSheetModal>
>(({ index = 0, backgroundStyle, style, handleIndicatorStyle, ...props }, ref) => {
  const { colors } = useColorScheme();

  const renderBackdrop = React.useCallback(
    (props: BottomSheetBackdropProps) => <BottomSheetBackdrop {...props} disappearsOnIndex={-1} />,
    []
  );
  return (
    <BottomSheetModal
      ref={ref}
      index={0}
      backgroundStyle={
        backgroundStyle ?? {
          backgroundColor: colors.card,
        }
      }
      style={
        style ?? {
          borderWidth: 1,
          borderColor: colors.grey5,
          borderTopStartRadius: 16,
          borderTopEndRadius: 16,
        }
      }
      handleIndicatorStyle={
        handleIndicatorStyle ?? {
          backgroundColor: colors.grey4,
        }
      }
      backdropComponent={renderBackdrop}
      {...props}
    />
  );
});

function useSheetRef() {
  return React.useRef<BottomSheetModal>(null);
}

export { Sheet, useSheetRef };

Usage

index.tsx
import { Button as RNButton, ButtonProps, Platform, View } from 'react-native';
import { Sheet, useSheetRef } from '~/components/nativewindui/Sheet';

import { Text } from '~/components/nativewindui/Text';
import { useColorScheme } from '~/lib/useColorScheme';

function DefaultButton({ color, ...props }: ButtonProps) {
  const { colors } = useColorScheme();
  return <RNButton color={color ?? colors.primary} {...props} />;
}

function BottomSheetExample() {
  const { colorScheme } = useColorScheme();
  const bottomSheetModalRef = useSheetRef();

  return (
    <View className="items-center">
      <DefaultButton
        color={colorScheme === 'dark' && Platform.OS === 'ios' ? 'white' : 'black'}
        title="Open Bottom Sheet"
        onPress={() => bottomSheetModalRef.current?.present()}
      />
      <Sheet ref={bottomSheetModalRef} snapPoints={[200]}>
        <View className="flex-1 items-center justify-center pb-8">
          <Text>@gorhom/bottom-sheet 🎉</Text>
        </View>
      </Sheet>
    </View>
  );
}
© Ronin Technologies LLC 2024