[🐛] Ghost like view on Android and iOS
🔥
Issue
There is a white ghost like view that probably has something related to keyboardVerticalOffset or your KeyboardCompatibleView (nor sure about this, just a hunch).
The observations are that on android, after the keyboard is dismissed this white view still remains on screen and does not get automatically dismissed. For IOS the bug seems milder, there is this white view that moves when a view on another zIndex changes its height.
Steps to reproduce
Steps to reproduce the behavior:
- Make a normal channel component as attached
- Change the client theme to dark theme so that you can see these white views
Expected behavior
This white view doesnt exist on Android or automatically gets dismissed, making it transparent on android would probably not help because it will still capture the touch events. This white moving view can be made transparent on iOS.
Project Related Information
Customization
Click To Expand
<Channel
MessageAvatar={(props) => <CustomMessageAvatar {...props} />}
channel={channel}
hasCommands={false}
keyboardVerticalOffset={iosVerticalOffset}
keyboardBehavior='padding'
thread={thread} threadList={!!thread}>
{thread ? (
<Thread />
) : (
<>
<MessageList onThreadSelect={(thread) => { setThread(thread) }} />
<MessageInput />
</>
)}
</Channel>
Offline support
- [ ] I have enabled offline support.
- [ ] The feature I'm having does not occur when offline support is disabled. (stripe out if not applicable)
Environment
Click To Expand
package.json:
{
"name": "",
"version": "1.0.0",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"test": "jest --watchAll",
"lint": "expo lint"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@expo/vector-icons": "^14.1.0",
"@notifee/react-native": "^9.1.8",
"@react-native-async-storage/async-storage": "2.1.2",
"@react-native-camera-roll/camera-roll": "^7.9.0",
"@react-native-community/checkbox": "^0.5.17",
"@react-native-community/cli-platform-android": "^15.1.3",
"@react-native-community/datetimepicker": "8.4.1",
"@react-native-community/netinfo": "11.4.1",
"@react-native-community/slider": "4.5.6",
"@react-native-firebase/app": "^22.4.0",
"@react-native-firebase/app-check": "^22.4.0",
"@react-native-firebase/auth": "^22.4.0",
"@react-native-firebase/firestore": "^22.4.0",
"@react-native-firebase/functions": "^22.4.0",
"@react-native-firebase/messaging": "^22.4.0",
"@react-native-firebase/storage": "^22.4.0",
"@react-navigation/drawer": "^7.1.1",
"@react-navigation/native": "^7.0.14",
"@stream-io/flat-list-mvcp": "^0.10.3",
"axios": "^1.11.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"expo": "^53.0.20",
"expo-av": "~15.1.7",
"expo-build-properties": "~0.14.8",
"expo-clipboard": "~7.1.5",
"expo-constants": "~17.1.7",
"expo-dev-client": "~5.2.4",
"expo-document-picker": "~13.1.6",
"expo-file-system": "~18.1.11",
"expo-font": "~13.3.2",
"expo-haptics": "~14.1.4",
"expo-image-manipulator": "~13.1.7",
"expo-image-picker": "~16.1.4",
"expo-linking": "~7.1.7",
"expo-localization": "~16.1.6",
"expo-location": "~18.1.6",
"expo-media-library": "~17.1.7",
"expo-router": "~5.1.4",
"expo-sharing": "~13.1.5",
"expo-splash-screen": "~0.30.10",
"expo-system-ui": "~5.0.10",
"expo-web-browser": "~14.2.0",
"fast-xml-parser": "^4.4.0",
"i18next": "^24.2.3",
"openai": "^4.47.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-i18next": "^15.4.1",
"react-native": "0.79.5",
"react-native-currency-input": "^1.1.1",
"react-native-element-dropdown": "^2.12.0",
"react-native-geolocation-service": "^5.3.1",
"react-native-gesture-handler": "~2.24.0",
"react-native-get-random-values": "~1.11.0",
"react-native-google-places-textinput": "file:./modules/react-native-google-places-textinput",
"react-native-image-crop-picker": "^0.41.1",
"react-native-mmkv": "^3.2.0",
"react-native-progress-steps": "^1.3.4",
"react-native-purchases": "^8.5.0",
"react-native-purchases-ui": "^8.5.0",
"react-native-reanimated": "~3.17.4",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-sha256": "^1.4.10",
"react-native-star-rating-widget": "^1.9.1",
"react-native-svg": "15.11.2",
"react-native-web": "^0.20.0",
"stream-chat-expo": "^8.3.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@react-native-community/cli": "^15.1.3",
"typescript": "~5.8.3"
},
"private": true
}
react-native info output:
System:
OS: macOS 15.2
CPU: (8) arm64 Apple M2
Memory: 166.34 MB / 8.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 23.10.0
path: /opt/homebrew/bin/node
Yarn:
version: 1.22.22
path: /opt/homebrew/bin/yarn
npm:
version: 10.9.2
path: /opt/homebrew/bin/npm
Watchman:
version: 2025.03.10.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 24.0
- iOS 18.0
- macOS 15.0
- tvOS 18.0
- visionOS 2.0
- watchOS 11.0
Android SDK: Not Found
IDEs:
Android Studio: 2025.1 AI-251.26094.121.2512.13840223
Xcode:
version: 16.0/16A242d
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.11
path: /usr/bin/javac
Ruby:
version: 3.4.1
path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 15.1.3
wanted: ^15.1.3
react:
installed: 19.0.0
wanted: 19.0.0
react-native:
installed: 0.79.5
wanted: 0.79.5
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
- Platform that you're experiencing the issue on:
- [ x] iOS
- [ x] Android
- [ ] iOS but have not tested behavior on Android
- [ ] Android but have not tested behavior on iOS
- [ x] Both
stream-chat-react-nativeversion you're using that has this issue:8.3.1
- Device/Emulator info:
- [ x] I am using a physical device
- OS version:
Android 12 - Device/Emulator:
iPhone 16
Additional context
Screenshots
Click To Expand
https://github.com/user-attachments/assets/ef220d4f-e8e0-4efa-90db-476ade9e2946 https://github.com/user-attachments/assets/1f1d76ad-d9a7-456f-b246-251871d18535
i am facing same issue
@2200software is your issue resolved ?
nope, still the same
no its a bug in latest version, the bottomsheet attachment picker gets toggled each time keyboard is closed.
I found version 7.2.8 most stable, use that one, 8.x is still in beta I think with so many bugs.
work around
useEffect(() => {
const didHide = Keyboard.addListener("keyboardDidHide", () => {
closeAttachmentPicker();
});
return () => {
didHide.remove();
};
}, []);
you can expect a slight lag when the keyboard hides and the bottomsheet closes, we have to wait until the developers decide to work on it and fix it
https://github.com/user-attachments/assets/f1eb138c-765e-4faa-8fa3-53a0d45dc8c2
no its a bug in latest version, the bottomsheet attachment picker gets toggled each time keyboard is closed.
I found version 7.2.8 most stable, use that one, 8.x is still in beta I think with so many bugs.
work around
useEffect(() => { const didHide = Keyboard.addListener("keyboardDidHide", () => { closeAttachmentPicker(); }); return () => { didHide.remove(); }; }, []); you can expect a slight lag when the keyboard hides and the bottomsheet closes, we have to wait until the developers decide to work on it and fix it
Record_2025-09-10-04-13-04_00ed75b494686ed80a675e715cb7f4c4.mp4
I’m using that version but still experiencing the issue. I have wrapped all of my screens inside the Chat component, and that seems to be causing the problem across every screen. When I commented out the wrapper and ran the code, it worked fine.
I’ve patched the package locally and it resolves the ghost issue on both Android and iOS.
"stream-chat-react-native": "8.5.2",
"react-native": "0.80.2",
What was fixed:
- Gallery thumbnails: Removed the
-1offset on height/width and simplified container styles. This prevents the ghost overlay effect on images. - Thumbnail building: Always using
covermode for resize, so thumbnails consistently fill their container instead of leaving gaps. - Attachment picker & keyboard: Removed the keyboard event listener that was closing/reopening the picker whenever the keyboard appeared. Now, the picker only responds to user interaction (tapping the attachment button), which resolves the annoying picker/keyboard conflict.
Here is the full patch:
patches/stream-chat-react-native-core+8.5.2.patch
index 7da851d..884ea42 100644
--- a/node_modules/stream-chat-react-native-core/src/components/Attachment/Gallery.tsx
+++ b/node_modules/stream-chat-react-native-core/src/components/Attachment/Gallery.tsx
@@ -448,8 +448,8 @@ const GalleryImageThumbnail = ({
<View
style={[
{
- height: thumbnail.height - 1,
- width: thumbnail.width - 1,
+ height: thumbnail.height,
+ width: thumbnail.width,
},
gallery.thumbnail,
]}
@@ -476,8 +476,8 @@ const GalleryImageThumbnail = ({
style={[
borderRadius,
{
- height: thumbnail.height - 1,
- width: thumbnail.width - 1,
+ height: thumbnail.height,
+ width: thumbnail.width,
},
gallery.image,
]}
@@ -685,9 +685,8 @@ const styles = StyleSheet.create({
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
- padding: 1,
},
- imageContainerStyle: { alignItems: 'center', flex: 1, justifyContent: 'center' },
+ imageContainerStyle: { alignItems: 'center', justifyContent: 'center' },
imageLoadingErrorIndicatorStyle: {
bottom: 4,
left: 4,
diff --git a/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts b/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
index 3132979..c4bb64f 100644
--- a/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
+++ b/node_modules/stream-chat-react-native-core/src/components/Attachment/utils/buildGallery/buildThumbnail.ts
@@ -36,7 +36,7 @@ export function buildThumbnail({
height,
resizeMode: resizeMode
? resizeMode
- : ((image.original_height && image.original_width ? 'contain' : 'cover') as ImageResizeMode),
+ : ('cover' as ImageResizeMode), // Always use 'cover' to fill the container completely
thumb_url: image.thumb_url,
type: image.type,
url: shouldResize
diff --git a/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx b/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
index 18ff1f1..7327ba2 100644
--- a/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
+++ b/node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
@@ -178,29 +178,11 @@ export const AttachmentPicker = React.forwardRef(
return () => backHandler.remove();
}, [selectedPicker, closePicker, setSelectedPicker]);
- useEffect(() => {
- const onKeyboardOpenHandler = () => {
- if (selectedPicker) {
- setSelectedPicker(undefined);
- }
- closePicker();
- };
- const keyboardShowEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
- const keyboardSubscription = Keyboard.addListener(keyboardShowEvent, onKeyboardOpenHandler);
-
- return () => {
- // Following if-else condition to avoid deprecated warning coming RN 0.65
- if (keyboardSubscription?.remove) {
- keyboardSubscription.remove();
- return;
- }
- // @ts-ignore
- else if (Keyboard.removeListener) {
- // @ts-ignore
- Keyboard.removeListener(keyboardShowEvent, onKeyboardOpenHandler);
- }
- };
- }, [closePicker, selectedPicker, setSelectedPicker]);
+ // Removed keyboard event listener that was causing the attachment picker
+ // to close when keyboard opens. The picker should only be controlled by
+ // user interaction (clicking the attachment button), not by keyboard events.
+ // This prevents the unwanted behavior where the picker becomes visible
+ // when the keyboard opens.
useEffect(() => {
if (currentIndex < 0) {
This change has fixed my issue — possibly BottomSheetFlatList renders an empty scroll container even when the data array is empty. This empty container still takes layout space inside the BottomSheet, causing the sheet to open or expand unexpectedly.
node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
{selectedPhotos?.length > 0 && (
<BottomSheetFlatList
...
/>
)}
// Fix: FlatList takes full space even with empty data, causing BottomSheet to open.
// So render FlatList only when photos are available.
{selectedPhotos?.length > 0 && (
<BottomSheetFlatList
contentContainerStyle={[
styles.container,
{ backgroundColor: white },
bottomSheetContentContainer,
{ opacity: photoError ? 0 : 1 },
]}
data={selectedPhotos}
keyExtractor={(item) => item.asset.uri}
numColumns={numberOfAttachmentPickerImageColumns ?? 3}
onEndReached={photoError ? undefined : getMorePhotos}
renderItem={renderAttachmentPickerItem}
testID={'attachment-picker-list'}
/>
)}
An alternative workaround that appears to be effective is forcing the resolution of @gorhom/bottom-sheet to version 5.1.4. Versions above 5.1.4 seem to result in this issue.
The override object is placed in package.json:
"overrides": {
"stream-chat-react-native-core": {
"@gorhom/bottom-sheet": "5.1.4"
}
}
See also https://github.com/GetStream/stream-chat-react-native/issues/1741
For our project we are still on Stream 7.3.0 so unsure if this workaround would be effective on version 8 or higher, but may be a simpler approach versus patching.
This change has fixed my issue — possibly BottomSheetFlatList renders an empty scroll container even when the data array is empty. This empty container still takes layout space inside the BottomSheet, causing the sheet to open or expand unexpectedly.
node_modules/stream-chat-react-native-core/src/components/AttachmentPicker/AttachmentPicker.tsx
{selectedPhotos?.length > 0 && ( <BottomSheetFlatList ... /> )}// Fix: FlatList takes full space even with empty data, causing BottomSheet to open. // So render FlatList only when photos are available. {selectedPhotos?.length > 0 && ( <BottomSheetFlatList contentContainerStyle={[ styles.container, { backgroundColor: white }, bottomSheetContentContainer, { opacity: photoError ? 0 : 1 }, ]} data={selectedPhotos} keyExtractor={(item) => item.asset.uri} numColumns={numberOfAttachmentPickerImageColumns ?? 3} onEndReached={photoError ? undefined : getMorePhotos} renderItem={renderAttachmentPickerItem} testID={'attachment-picker-list'} /> )}
This will "fix" the issue but then you won't see any recent images in the tray when you go to add a photo.