Bottom Sheet Stepper

repository·main·Indexed 43 days ago

https://github.com/mahdidavoodi7/bottom-sheet-stepper

A self-resizing, multi-step bottom sheet component for React Native and Expo, version 0.2.0. Designed for fintech and crypto app interactions, it allows developers to create multi-step flows with shared typed data and programmatic control via BottomSheetStepperRef (present/dismiss). Requires react-native-reanimated, react-native-gesture-handler, and @gorhom/bottom-sheet.

Tokens
3.7K
Snippets
13
Records
17
Agent score
54%

What's inside Bottom Sheet Stepper

  1. Share typed data across steps using the `shared` prop

    main

    You can pass a shared object to BottomSheetStepper. This object is automatically injected into every step function via StepComponentProps. The type of shared is inferred from the object you provide, ensuring type safety within your step components without manual casting.

    // `user` is your own data — its type flows into every step, no annotation needed
    <BottomSheetStepper
      ref={stepperRef}
      shared={{ user }}
      initialStep={0}
      steps={[
        ({ shared, onNextPress }) => (
          <AccountStep user={shared.user} onNext={onNextPress} />
        ),
        ({ shared, onEnd }) => (
          <ConfirmStep user={shared.user} onDone={onEnd} />
        ),
      ]}
    />;
  2. Configure GestureHandlerRootView and BottomSheetModalProvider

    main

    Before using the stepper, ensure your application is wrapped in GestureHandlerRootView and BottomSheetModalProvider so the sheet and gestures function correctly.

    import { GestureHandlerRootView } from "react-native-gesture-handler";
    import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
    
    <GestureHandlerRootView style={{ flex: 1 }}>
      <BottomSheetModalProvider>
        <App />
      </BottomSheetModalProvider>
    </GestureHandlerRootView>;
  3. Install Bottom Sheet Stepper and peer dependencies

    main

    To use bottom-sheet-stepper, you can either copy BottomSheetStepper.tsx directly from the source or install it via npm. You must also install the required peer dependencies: react-native-reanimated, react-native-gesture-handler, and @gorhom/bottom-sheet.

    npm install react-native-reanimated react-native-gesture-handler @gorhom/bottom-sheet
  4. Use BottomSheetStepper to create a multi-step flow

    main

    To implement a stepper, create a component for each step that accepts StepComponentProps. Use a useRef with the BottomSheetStepperRef type to control the stepper. You can trigger the flow by calling .present() on the ref.

    import { useRef } from "react";
    import { View, Text, Button } from "react-native";
    import BottomSheetStepper, {
      BottomSheetStepperRef,
      StepComponentProps,
    } from "bottom-sheet-stepper";
    
    const Step1 = ({ onNextPress }: StepComponentProps) => (
      <View>
        <Text>Step 1</Text>
        <Button title="Next" onPress={onNextPress} />
      </View>
    );
    
    const Step2 = ({ onBackPress, onEnd }: StepComponentProps) => (
      <View>
        <Text>Step 2</Text>
        <Button title="Back" onPress={onBackPress} />
        <Button title="Finish" onPress={onEnd} />
      </View>
    );
    
    const App = () => {
      const stepperRef = useRef<BottomSheetStepperRef>(null);
    
      return (
        <>
          <Button title="Open" onPress={() => stepperRef.current?.present()} />
          <BottomSheetStepper ref={stepperRef} steps={[Step1, Step2]} />
        </>
      );
    };
  5. Configure BottomSheetStepperProps

    main

    The BottomSheetStepperProps<TShared> object defines how the stepper behaves and what data it carries:

    • steps: An array of functions that return a React.ReactNode. Each function receives StepComponentProps<TShared>.
    • shared: Data passed to every step. The type of this prop is used to infer the type of shared inside each step's props.
    • initialStep: The zero-based index where the flow starts and returns to upon closing. Defaults to 0.
    • style: Custom style for the content container.
    • bottomInset: Padding at the bottom of the sheet. Defaults to 20.
    • horizontalInset: Horizontal margin for the bottom sheet. Defaults to 24.
    • disablePanDownToClose: If true, prevents the user from swiping the sheet down to close it.
    • disableBackDropPressToClose: If true, prevents tapping the backdrop from dismissing the sheet.
  6. Reference: BottomSheetStepper props

    main

    The BottomSheetStepper component accepts the following props to customize the stepper behavior and appearance:

    PropTypeDescription
    steps((props: StepComponentProps<TShared>) => React.ReactNode)[]Your steps, in order
    sharedTSharedData passed to every step, typed and inferred from what you hand it
    initialStepnumberStep index the flow opens on and resets to (default 0)
    styleStyleProp<ViewStyle>Style for the step container
    bottomInsetnumberPadding at the bottom (default 20)
    horizontalInsetnumberSide margin so the card floats (default 24)
    disablePanDownToClosebooleanTurn off swipe-to-close
    disableBackDropPressToClosebooleanKeep taps on the backdrop from closing it
  7. Use the BottomSheetStepper component

    main

    The BottomSheetStepper component is a React Native component that manages a multi-step flow within a bottom sheet modal. It uses a list of render functions as steps and supports sharing data across all steps via a shared prop.

    To control the stepper (opening or closing it), you must use a ref and call its imperative methods.

    import React, { useRef } from 'react';
    import BottomSheetStepper, { BottomSheetStepperRef } from './BottomSheetStepper';
    
    const MyFlow = () => {
      const stepperRef = useRef<BottomSheetStepperRef>(null);
    
      const startFlow = () => {
        stepperRef.current?.present();
      };
    
      return (
        <>
          <Button title="Start" onPress={startFlow} />
          <BottomSheetStepper
            ref={stepperRef}
            shared={{ userId: '123' }}
            steps={[
              ({ onNextPress, shared }) => (
                <View>
                  <Text>User ID: {shared.userId}</Text>
                  <Button title="Next" onPress={onNextPress} />
                </View>
              ),
              ({ onBackPress, onNextPress }) => (
                <View>
                  <Button title="Back" onPress={onBackPress} />
                  <Button title="Finish" onPress={onNextPress} />
                </View>
              ),
            ]}
          />
        </>
      );
    };
  8. Implement step components with StepComponentProps

    main

    Each function in the steps array receives a StepComponentProps<TShared> object. Use these props to navigate the flow and access shared state:

    • onNextPress: Call this to move to the next step. If it is the last step, the sheet will close.
    • onBackPress: Call this to move to the previous step. If it is the first step, the sheet will close.
    • onEnd: Call this to manually close the sheet (useful for completion actions).
    • shared: The data provided via the shared prop on the main BottomSheetStepper component. It is automatically typed based on the shared prop.
    type MyData = { name: string };
    
    const steps = [
      ({ onNextPress, shared }: StepComponentProps<MyData>) => (
        <View>
          <Text>{shared.name}</Text>
          <Button title="Next" onPress={onNextPress} />
        </View>
      )
    ];
  9. Use StepComponentProps to access shared data and navigation

    main

    Each function in the steps array receives a StepComponentProps<TShared> object. This object provides the necessary tools to navigate the stepper and access data shared across the entire flow.

    Properties

    • onNextPress: Function to trigger the transition to the next step.
    • onBackPress: Function to trigger the transition to the previous step.
    • onEnd: Optional callback triggered when the stepper reaches the end of the flow.
    • shared: The data passed from the shared prop of the BottomSheetStepper. It is typed via the TShared generic, allowing for type-safe access to shared state without manual casting.
    type MySharedData = { name: string };
    
    const steps = [
      ({ shared, onNextPress }: StepComponentProps<MySharedData>) => (
        <View>
          <Text>{shared.name}</Text>
          <Button title="Next" onPress={onNextPress} />
        </View>
      ),
    ];