Bug description
On the New Architecture (Fabric), the iOS WKWebView is created fully transparent (opaque = NO, no background color). Any region of the web content that has transparent CSS shows whatever is behind the RN surface — typically the black UIWindow — and the same black/blank areas appear in the snapshot layers during allowsBackForwardNavigationGestures swipe transitions.
The same app and the same web content render correctly (opaque white webview) on the old architecture (Paper). This is a regression introduced by the architecture switch, not by the web content.
Environment
|
|
| react-native-webview |
14.0.1 |
| react-native |
0.86.2 (New Architecture / Fabric — mandatory since RN 0.82) |
| Platform |
iOS (reproduced on iPhone 14 real device and iOS simulator) |
| Old architecture (RN 0.77.3 + webview 13.16.0, same app/web content) |
not reproducible — webview is opaque white as expected |
To Reproduce
-
Create a New Architecture RN app (RN 0.82+).
-
Render a plain <WebView source={{ uri }} /> (no style prop) pointing to any page that contains transparent regions, e.g.:
<body style="background: transparent">
<div style="height: 50vh; background: white">opaque part</div>
<!-- rest of the body is transparent -->
</body>
-
Run on iOS.
Screenshots/Videos
banner/icon chips (web-painted) render fine; the page background the web leaves transparent shows the black window through
Expected behavior
Expected: transparent CSS regions render on an opaque white webview background — this is both the Paper behavior and what the library's own JS default style
requests (webView: { backgroundColor: '#ffffff' }, see "Root cause analysis" below).
Actual: transparent regions show the black window behind the RN surface. Also visible as black/blank sheets during back/forward swipe-gesture transitions.
Root cause analysis
RNCWebViewImpl derives the webview's opacity from the last color passed to setBackgroundColor: and applies it when the WKWebView is created:
// RNCWebViewImpl.m — didMoveToWindow
_webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
[self setBackgroundColor: _savedBackgroundColor];
// RNCWebViewImpl.m — setBackgroundColor:
CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
BOOL opaque = (alpha == 1.0);
self.opaque = _webView.opaque = opaque;
_webView.scrollView.backgroundColor = backgroundColor;
_webView.backgroundColor = backgroundColor;
- On Paper, the view-manager prop dispatch calls
setBackgroundColor: automatically, delivering the library's own JS default style (src/WebView.styles.ts → webView: { backgroundColor: '#ffffff' }). Result: _savedBackgroundColor = white, opaque = YES.
- On Fabric, the component wrapper (
apple/RNCWebView.mm) never reads ViewProps.backgroundColor and never forwards it to RNCWebViewImpl — the base RCTViewComponentView consumes the prop by painting its own layer instead. _savedBackgroundColor therefore stays nil, CGColorGetAlpha(nil.CGColor) evaluates to 0, and the webview is configured transparent.
In other words, the implementation has always depended on the framework forwarding backgroundColor into the impl, and that (implicit, reflection-based) delivery no longer exists under Fabric.
Proposed fix
Forward the standard backgroundColor view prop to the impl in RNCWebView.mm's updateProps:oldProps:, e.g.:
const auto &oldViewProps = *std::static_pointer_cast<const RNCWebViewProps>(_props);
const auto &newViewProps = *std::static_pointer_cast<const RNCWebViewProps>(props);
if (oldViewProps.backgroundColor != newViewProps.backgroundColor) {
[_view setBackgroundColor:RCTUIColorFromSharedColor(newViewProps.backgroundColor)];
}
Since the JS layer already ships backgroundColor: '#ffffff' in the default style, wiring the relay restores Paper parity without further changes, and also makes intentional transparent webviews (style={{ backgroundColor: 'transparent' }}) work as documented.
Happy to open a PR for this if the direction is agreed.
Bug description
On the New Architecture (Fabric), the iOS
WKWebViewis created fully transparent (opaque = NO, no background color). Any region of the web content that has transparent CSS shows whatever is behind the RN surface — typically the blackUIWindow— and the same black/blank areas appear in the snapshot layers duringallowsBackForwardNavigationGesturesswipe transitions.The same app and the same web content render correctly (opaque white webview) on the old architecture (Paper). This is a regression introduced by the architecture switch, not by the web content.
Environment
To Reproduce
Create a New Architecture RN app (RN 0.82+).
Render a plain
<WebView source={{ uri }} />(nostyleprop) pointing to any page that contains transparent regions, e.g.:Run on iOS.
Screenshots/Videos
banner/icon chips (web-painted) render fine; the page background the web leaves transparent shows the black window through
Expected behavior
Expected: transparent CSS regions render on an opaque white webview background — this is both the Paper behavior and what the library's own JS default style
requests (
webView: { backgroundColor: '#ffffff' }, see "Root cause analysis" below).Actual: transparent regions show the black window behind the RN surface. Also visible as black/blank sheets during back/forward swipe-gesture transitions.
Root cause analysis
RNCWebViewImplderives the webview's opacity from the last color passed tosetBackgroundColor:and applies it when theWKWebViewis created:setBackgroundColor:automatically, delivering the library's own JS default style (src/WebView.styles.ts→webView: { backgroundColor: '#ffffff' }). Result:_savedBackgroundColor = white,opaque = YES.apple/RNCWebView.mm) never readsViewProps.backgroundColorand never forwards it toRNCWebViewImpl— the baseRCTViewComponentViewconsumes the prop by painting its own layer instead._savedBackgroundColortherefore staysnil,CGColorGetAlpha(nil.CGColor)evaluates to0, and the webview is configured transparent.In other words, the implementation has always depended on the framework forwarding
backgroundColorinto the impl, and that (implicit, reflection-based) delivery no longer exists under Fabric.Proposed fix
Forward the standard
backgroundColorview prop to the impl inRNCWebView.mm'supdateProps:oldProps:, e.g.:Since the JS layer already ships
backgroundColor: '#ffffff'in the default style, wiring the relay restores Paper parity without further changes, and also makes intentional transparent webviews (style={{ backgroundColor: 'transparent' }}) work as documented.Happy to open a PR for this if the direction is agreed.