Description
Description
On iOS with Fabric (New Architecture) enabled, RefreshControl props like tintColor, title, and titleColor are not applied on initial mount. This causes the refresh spinner to be invisible against dark backgrounds (e.g., dark mode).
Root Cause
In RCTPullToRefreshViewComponentView.mm, the updateProps:oldProps: method uses *_props instead of *oldProps when constructing oldConcreteProps:
// Line 79 — current (buggy)
const auto &oldConcreteProps = static_cast<const PullToRefreshViewProps &>(*_props);
Before the initial layout, updateProps stores incoming props into _props and returns early (lines 74–76). Then layoutSubviews replays the update:
[self updateProps:_props oldProps:PullToRefreshViewShadowNode::defaultSharedProps()];
Here, _props (new) and oldProps (default) are different objects, so the comparison should detect changes. However, because line 79 reads from *_props instead of *oldProps, oldConcreteProps and newConcreteProps both resolve to the same stored _props object. All comparisons evaluate to equal, so no props are applied to _refreshControl.
Fix
Change line 79 to use the oldProps parameter:
// Fixed
const auto &oldConcreteProps = static_cast<const PullToRefreshViewProps &>(*oldProps);
Expected Behavior
The refresh spinner should use the specified tintColor on initial mount.
Actual Behavior
The tintColor prop is silently ignored on initial mount. The UIRefreshControl retains its default appearance.
React Native Version
0.81.5 (confirmed present, but likely affects all Fabric-enabled versions since the deferred-props logic was introduced)
Affected Platforms
iOS (Fabric only)
Steps to reproduce
- Enable New Architecture (Fabric) in an iOS app
- Use a dark background (e.g., dark mode)
- Add a RefreshControl with tintColor set to a light color (e.g., #ffffff)
- Pull to refresh — the spinner is invisible because it uses the default color (dark) instead of the specified tintColor
React Native Version
0.81.5
Affected Platforms
Runtime - iOS
Areas
Fabric - The New Renderer
Output of npx @react-native-community/cli info
System:
OS: macOS 26.4
CPU: (11) arm64 Apple M3 Pro
Memory: 1.53 GB / 36.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 20.19.5
Yarn:
version: 1.22.22
npm:
version: 10.8.2
Watchman:
version: 2026.03.16.00
Managers:
CocoaPods:
version: 1.16.2
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
Android SDK: Not Found
IDEs:
Android Studio: 2025.3 AI-253.30387.90.2532.14935130
Xcode:
version: 26.3/17C529
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.16
Ruby:
version: 3.4.3
npmPackages:
"@react-native-community/cli":
installed: 20.1.1
wanted: 20.1.1
react:
installed: 19.1.0
wanted: 19.1.0
react-native:
installed: 0.81.5
wanted: 0.81.5
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
info React Native v0.84.1 is now available (your project is running on v0.81.5).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.84.1
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.81.5&to=0.84.1
info For more info, check out "https://reactnative.dev/docs/upgrading?os=macos".
Stacktrace or Logs
MANDATORY Reproducer
https://github.com/mikaelkristiansson/RefreshControlBug
Screenshots and Videos
No response
Description
Description
On iOS with Fabric (New Architecture) enabled, RefreshControl props like tintColor, title, and titleColor are not applied on initial mount. This causes the refresh spinner to be invisible against dark backgrounds (e.g., dark mode).
Root Cause
In RCTPullToRefreshViewComponentView.mm, the updateProps:oldProps: method uses *_props instead of *oldProps when constructing oldConcreteProps:
Before the initial layout, updateProps stores incoming props into _props and returns early (lines 74–76). Then layoutSubviews replays the update:
[self updateProps:_props oldProps:PullToRefreshViewShadowNode::defaultSharedProps()];
Here, _props (new) and oldProps (default) are different objects, so the comparison should detect changes. However, because line 79 reads from *_props instead of *oldProps, oldConcreteProps and newConcreteProps both resolve to the same stored _props object. All comparisons evaluate to equal, so no props are applied to _refreshControl.
Fix
Change line 79 to use the oldProps parameter:
Expected Behavior
The refresh spinner should use the specified tintColor on initial mount.
Actual Behavior
The tintColor prop is silently ignored on initial mount. The UIRefreshControl retains its default appearance.
React Native Version
0.81.5 (confirmed present, but likely affects all Fabric-enabled versions since the deferred-props logic was introduced)
Affected Platforms
iOS (Fabric only)
Steps to reproduce
React Native Version
0.81.5
Affected Platforms
Runtime - iOS
Areas
Fabric - The New Renderer
Output of
npx @react-native-community/cli infoStacktrace or Logs
MANDATORY Reproducer
https://github.com/mikaelkristiansson/RefreshControlBug
Screenshots and Videos
No response