Liquid Glass header shadows incorrectly invert when FlatList has inverted={true} on iOS 26
Description
Expected Behavior
When using inverted={true} FlatList, the header shadow/blur should maintain its normal appearance with proper content darkening underneath the transparent header.
Actual Behavior
Liquid Glass interface automatically detects the FlatList inversion and incorrectly inverts the header blur gradient. This causes:
- All visible content under the header becomes properly darkened (incorrect)
- All content that should be darkened under the header remains fully transparent (incorrect)
The shadow/blur gradient is effectively inverted, creating the opposite visual effect.
migrated from https://github.com/software-mansion/react-native-screens/issues/3293
Steps to reproduce
- Setting up
headerTransparent: trueif using Navigation OR add native elements to ViewController (Searchbar etc.) - Add a FlatList with inverted={true} OR apply transform: [{ scaleY: -1 }]
- Scroll the list and observe the header shadow behavior
- Compare with a non-inverted FlatList
React Native Version
0.81.4
Affected Platforms
Runtime - iOS
Output of npx @react-native-community/cli info
System:
OS: macOS 26.0.1
CPU: (11) arm64 Apple M3 Pro
Memory: 184.17 MB / 18.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.14.0
path: /Users/vasgen/.nvm/versions/node/v22.14.0/bin/node
Yarn:
version: 3.6.1
path: /Users/vasgen/.nvm/versions/node/v22.14.0/bin/yarn
npm:
version: 10.9.2
path: /Users/vasgen/.nvm/versions/node/v22.14.0/bin/npm
Watchman:
version: 2025.03.03.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.0
- iOS 26.0
- macOS 26.0
- tvOS 26.0
- visionOS 26.0
- watchOS 26.0
Android SDK:
API Levels:
- "34"
Build Tools:
- 29.0.2
- 32.0.0
- 34.0.0
System Images:
- android-34 | Google Play ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2024.2 AI-242.23339.11.2421.12483815
Xcode:
version: 26.0.1/17A400
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.14
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 19.1.0
wanted: 19.1.0
react-native:
installed: 0.81.4
wanted: 0.81.4
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Stacktrace or Logs
-
MANDATORY Reproducer
https://snack.expo.dev/@whidrubeld/liquid-glass-header-shadows-incorrectly-invert-when-flatlist-has-inverted
Screenshots and Videos
Example of behavior
ViewController setting up
I was able to reproduce this issue.
Seeing this same issue. Is there any documented workaround at this point?
I've been waiting for a solution to this too. https://github.com/expo/expo/issues/40409
Seeing this same issue. Is there any documented workaround at this point?
Not that I've seen. My workaround is to set headerTransparent: false and then adjust padding accordingly. Either that or use a non-inverted list.
Between those two options having a temporary opaque header is the lesser evil. Having a non-inverted list is more of a hassle in my case.
Seeing this same issue. Is there any documented workaround at this point?
dentified the following "workaround" solutions:
- Disable transparent style for native elements;
- Develop JS equivalents of the same elements;
- Use LegendList as an equivalent.
In my scenarios, I quickly developed JS equivalents, since LegendList functionality turned out to be insufficient. Haven't studied the native layer issues yet.
This is because UIScrollEdgeEffect introduced in iOS 26.
A temp workaround for new Arch is to apply this patch:
diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
index c593d9e..161a804 100644
--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
@@ -41,6 +41,13 @@ - (instancetype)initWithFrame:(CGRect)frame
// scrollbar flip because we also flip it with whole `UIScrollView` flip.
self.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight;
+ if (@available(iOS 26.0, *)) {
+ self.topEdgeEffect.hidden = YES;
+// self.bottomEdgeEffect.hidden = YES;
+// self.leftEdgeEffect.hidden = YES;
+// self.rightEdgeEffect.hidden = YES;
+ }
+
__weak __typeof(self) weakSelf = self;
_delegateSplitter = [[RCTGenericDelegateSplitter alloc] initWithDelegateUpdateBlock:^(id delegate) {
[weakSelf setPrivateDelegate:delegate];
Uncomment the edges you want to disable blur effect of. For this issue, an inverted vertical scroll view, it is the top edge. Be attention, this patch will affect all scrollview.
For old arch I didn't try, maybe you should add these lines to RCTScrollView.m
I'd like to open a PR to expose these four props, but I need to learn how to codegen from flowjs first.
This is because UIScrollEdgeEffect introduced in iOS 26.
A temp workaround for new Arch is to apply this patch:
diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm index c593d9e..161a804 100644 --- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm +++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm @@ -41,6 +41,13 @@ - (instancetype)initWithFrame:(CGRect)frame // scrollbar flip because we also flip it with whole
UIScrollViewflip. self.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight;
- if (@available(iOS 26.0, *)) {
self.topEdgeEffect.hidden = YES;+// self.bottomEdgeEffect.hidden = YES; +// self.leftEdgeEffect.hidden = YES; +// self.rightEdgeEffect.hidden = YES;
- }
- __weak __typeof(self) weakSelf = self; _delegateSplitter = [[RCTGenericDelegateSplitter alloc] initWithDelegateUpdateBlock:^(id delegate) { [weakSelf setPrivateDelegate:delegate]; Uncomment the edges you want to disable blur effect of. For this issue, an inverted vertical scroll view, it is the top edge. Be attention, this patch will affect all scrollview.
For old arch I didn't try, maybe you should add these lines to
RCTScrollView.mI'd like to open a PR to expose these four props, but I need to learn how to codegen from flowjs first.
Idkw, but it didn't work for me. I updated RCTScrollViewComponentView.mm instead to catch the inverted behavior, so other ScrollViews still keep the blur effect
diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
index 1494fd2..f333818 100644
--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm
@@ -432,6 +432,15 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
}
[super updateProps:props oldProps:oldProps];
+
+ [self disableEdgeEffectIos26OnInverted];
+}
+
+- (void) disableEdgeEffectIos26OnInverted
+{
+ if (@available(iOS 26.0, *)) {
+ _scrollView.topEdgeEffect.hidden = [self isInverted];
+ }
}
- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState
@@ -762,6 +771,12 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
RCTSendScrollEventForNativeAnimations_DEPRECATED(scrollView, self.tag, kOnScrollEndEvent);
}
+- (void)layoutSubviews
+{
+ [super layoutSubviews];
+ [self disableEdgeEffectIos26OnInverted];
+}
+
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[self _handleFinishedScrolling:scrollView];
@@ -774,6 +789,8 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
if (!self.window) {
// The view is being removed, ensure that the scroll end event is dispatched
[self _handleScrollEndIfNeeded];
+ } else {
+ [self disableEdgeEffectIos26OnInverted];
}
}
Any updates on this issue? It's a gigantic blocker for me currently
@ahmed-sudowrite check out my comment regarding this issue on another repo for a quick workaround:
https://github.com/FaridSafi/react-native-gifted-chat/issues/2665#issuecomment-3609149121
@habovh yeah i've tried your solution, but for some reason I still have the same issue even with the transparent headers disabled. I'm not using the native headers at all so that might be why, i have headerShown: false everywhere, but it's worth noting that even when i do enable them and disable transparency the bug persists
@ahmed-sudowrite sorry to hear, frankly I really hope this bug gets fixed soon for everybody.
@whidrubeld @cipolleschi Hi! First of all, thank you for all your work on this project.
This is a huge blocker for my team currently- we're trying to ship a new version of our app with rn 0.83 this Friday Do you happen to have any estimates on when it might be fixed in a canary version of react native? Also, do you have any ideas for how it could be fixed? I'm eager to contribute a PR