react-native-bottom-sheet icon indicating copy to clipboard operation
react-native-bottom-sheet copied to clipboard

[Bug][iOS]: Incorrect keyboardBlurBehavior="restore" + keyboardBehavior="extend" Behavior in BottomSheetModal

Open lucksp opened this issue 2 months ago • 4 comments

Version

v5

Reanimated Version

v3

Gesture Handler Version

v2

Platforms

iOS

What happened?

This is the same thing originally posted in https://github.com/gorhom/react-native-bottom-sheet/issues/1887 which was closed.

Expected As a user, when I dismiss a keyboard, the bottom sheet modal should go back to its original position

Actual on iOS the bottom sheet does not go back to default/previous position.

https://github.com/user-attachments/assets/3fed0890-3529-48c1-80b9-6bf6c4a2acd7

Reproduction steps

  • ensure prop keyboardBehavior="extend"
  • Open Snack link
  • Present Modal
  • Focus the input
    • you will see keyboard appears + modal shifts up 👍
  • Press "done" button on keyboard
    • you will see keyboard disappears + modal stays shifted up 👎

Reproduction sample

https://snack.expo.dev/@lucksp/bottom-sheet---issue-reproduction-template

Relevant log output


lucksp avatar Oct 28 '25 22:10 lucksp

Similar thing is happening for me. I have keyboardBehavior="interactive" when I open the keyboard the sheet moves up and when I dismiss the keyboard sheet remains at the top. This part of the code is not returning the correct index. I have managed to put a fix in my locally installed package code. Basically the currentIndex in this code is incorrect when keyboard closes:

Image

HassanKhan96 avatar Nov 05 '25 10:11 HassanKhan96

I fixed it locally by going into the node_modules and gorhom folder, finding this section in BottomSheet component and adding this in the if statement:

if ( source === ANIMATION_SOURCE.KEYBOARD && keyboardBlurBehavior === KEYBOARD_BLUR_BEHAVIOR.restore && keyboardStatus === KEYBOARD_STATUS.HIDDEN && animatedContentGestureState.value !== State.ACTIVE && animatedHandleGestureState.value !== State.ACTIVE ) { isInTemporaryPosition.value = false; // return the previously active detent position when available, // otherwise fall back to the first detent const nextPosition = currentIndex >= 0 && detents && currentIndex < detents.length ? detents[currentIndex] : detents[0]; return nextPosition; }

HassanKhan96 avatar Nov 05 '25 10:11 HassanKhan96

@HassanKhan96 it doesn't work in my case.

Image
<BottomSheet
      ref={sheetRef}
      index={-1}
      snapPoints={snapPoints}
      enableDynamicSizing={false}
      onChange={onChangeSheet}
      enablePanDownToClose
      backdropComponent={renderBackdrop}
      keyboardBehavior="interactive"
      keyboardBlurBehavior="restore"
      android_keyboardInputMode="adjustPan"
      enableBlurKeyboardOnGesture={true}
      containerStyle={{ marginTop: insets.top }}
      enableOverDrag={false}
      handleStyle={{ backgroundColor: handleBackgroundColor }}
    >
.......
</BottomSheet>

mansi-avesta-rev avatar Nov 06 '25 07:11 mansi-avesta-rev

It works fine here on Android and iOS (native), but when I access it on the iOS web interface, BottomSheetModal behaves strangely when focusing on inputs. Does anyone know how to solve this?

Image
import React, { useEffect, useRef } from "react";
import { View, Platform } from "react-native";
import { useTheme } from "styled-components/native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import { useSheet } from "@/store/sheet";

import {
  BottomSheetModal,
  BottomSheetModalProvider,
  BottomSheetScrollView,
} from "@gorhom/bottom-sheet";
import { Button } from "@/components/ui/button";

import { X } from "lucide-react-native";

import { DEFAULT_PADDING } from "@/components/layout-constants";

export const SheetRoot = () => {
  const theme = useTheme();
  const insets = useSafeAreaInsets();
  const { content, isVisible, closeSheet, snapPoints } = useSheet();
  const modalRef = useRef(null);

  useEffect(() => {
    const timeout = setTimeout(() => {
      if (isVisible) {
        modalRef.current?.present();
      } else {
        modalRef.current?.dismiss();
      }
    }, 0);

    return () => clearTimeout(timeout);
  }, [isVisible]);

  return (
    <BottomSheetModalProvider>
      <BottomSheetModal
        ref={modalRef}
        onDismiss={closeSheet}
        snapPoints={snapPoints}
        keyboardBehavior="interactive"
        keyboardBlurBehavior="restore"
        enablePanDownToClose={Platform.OS !== "web"}
        android_keyboardInputMode="adjustResize"
        handleComponent={Platform.OS === "web" ? null : undefined}
        backdropComponent={({ style }) => (
          <View style={[style, { backgroundColor: "rgba(0, 0, 0, 0.85)" }]} />
        )}
        backgroundComponent={({ style }) => (
          <View style={(style, { backgroundColor: theme.colors.background })} />
        )}
        handleIndicatorStyle={{
          backgroundColor: theme.colors.input,
          marginTop: 8,
        }}
        handleStyle={{
          backgroundColor: theme.colors.background,
        }}
        style={{
          backgroundColor: theme.colors.background,
        }}
      >
        <BottomSheetScrollView
          keyboardShouldPersistTaps="handled"
          showsVerticalScrollIndicator={false}
          showsHorizontalScrollIndicator={false}
          contentContainerStyle={{
            paddingHorizontal: DEFAULT_PADDING,
            paddingTop: DEFAULT_PADDING / 2,
            paddingBottom: insets.bottom + DEFAULT_PADDING,
            backgroundColor: theme.colors.background,
          }}
        >
          <View
            style={{
              maxWidth: 600,
              width: "100%",
              margin: "auto",
            }}
          >
            {Platform.OS === "web" && (
              <View style={{ alignItems: "flex-end" }}>
                <Button variant="ghost" size="icon" onPress={closeSheet}>
                  <X size={18} />
                </Button>
              </View>
            )}
            {content || null}
          </View>
        </BottomSheetScrollView>
      </BottomSheetModal>
    </BottomSheetModalProvider>
  );
};

mannoeu avatar Nov 21 '25 21:11 mannoeu