📜 Description
When a screen uses KeyboardControllerView (via KeyboardProvider or useKeyboardHandler), the iOS status bar style is reset to its default whenever the keyboard animates in or out. On a light-themed screen configured with dark-content (dark icons), the icons turn white/invisible.
React Native's declarative <StatusBar barStyle="dark-content" /> does not self-correct because its internal _currentValues remains stale — _updatePropsStack only fires a native call when it sees a diff, and since _currentValues still shows dark-content, it skips the native call even though iOS has already reset the native state.
🔁 Steps to Reproduce
- Wrap a screen with
KeyboardProvider or use useKeyboardHandler in a component.
- Set
<StatusBar barStyle="dark-content" /> (light theme / dark icons).
- Focus a
TextInput to show the keyboard.
- Observe: status bar icons become white (reset to
light-content) while the keyboard animates in.
- Dismiss the keyboard — same reset occurs on the way out.
🔍 Root Cause
KeyboardControllerView.didMoveToWindow() calls keyboardTrackingView.attachToTopmostView(toWindow:), which adds a KeyboardTrackingView subview to the app's top view controller's view hierarchy during keyboard animation.
This view hierarchy mutation causes iOS to re-evaluate status bar appearance. iOS queries preferredStatusBarStyle from the key window's root view controller. During keyboard animation, the relevant window is UIRemoteKeyboardWindow (the private system keyboard input window), whose root view controller does not override preferredStatusBarStyle — so iOS falls back to .default / light-content.
React Native's StatusBar stack is not re-applied because it only calls the native module when _currentValues differs from the merged stack result, and the stale _currentValues hides the discrepancy.
✅ Current Workaround
Re-assert the style imperatively on every keyboard transition using useKeyboardHandler:
const reassertStatusBarStyle = useCallback(() => {
StatusBar.setBarStyle(statusBarStyle, true);
}, [statusBarStyle]);
const reassertStatusBarStyleWorklet = useCallback(() => {
'worklet';
if (Platform.OS === 'ios') {
scheduleOnRN(reassertStatusBarStyle);
}
}, [reassertStatusBarStyle]);
useKeyboardHandler(
{ onStart: reassertStatusBarStyleWorklet, onEnd: reassertStatusBarStyleWorklet },
[reassertStatusBarStyleWorklet],
);
This works but is boilerplate every consumer has to add and shouldn't be necessary.
💡 Suggested Fix
After attachToTopmostView() triggers a keyboard transition, call setNeedsStatusBarAppearanceUpdate() on the app's root view controller to force iOS to re-query preferredStatusBarStyle from the correct (app) view controller rather than the keyboard window's.
Alternatively, consider whether attachToTopmostView can be done in a way that avoids triggering iOS's status bar re-evaluation.
📋 Environment
|
|
react-native-keyboard-controller |
1.21.7 (confirmed present on 1.21.11) |
| Platform |
iOS |
| RN architecture |
New Architecture (Fabric) |
📸 Impact
Any app using KeyboardControllerView on a screen with a light theme and dark-content status bar will see the status bar icons disappear while the keyboard is animating.
📜 Description
When a screen uses
KeyboardControllerView(viaKeyboardProvideroruseKeyboardHandler), the iOS status bar style is reset to its default whenever the keyboard animates in or out. On a light-themed screen configured withdark-content(dark icons), the icons turn white/invisible.React Native's declarative
<StatusBar barStyle="dark-content" />does not self-correct because its internal_currentValuesremains stale —_updatePropsStackonly fires a native call when it sees a diff, and since_currentValuesstill showsdark-content, it skips the native call even though iOS has already reset the native state.🔁 Steps to Reproduce
KeyboardProvideror useuseKeyboardHandlerin a component.<StatusBar barStyle="dark-content" />(light theme / dark icons).TextInputto show the keyboard.light-content) while the keyboard animates in.🔍 Root Cause
KeyboardControllerView.didMoveToWindow()callskeyboardTrackingView.attachToTopmostView(toWindow:), which adds aKeyboardTrackingViewsubview to the app's top view controller's view hierarchy during keyboard animation.This view hierarchy mutation causes iOS to re-evaluate status bar appearance. iOS queries
preferredStatusBarStylefrom the key window's root view controller. During keyboard animation, the relevant window isUIRemoteKeyboardWindow(the private system keyboard input window), whose root view controller does not overridepreferredStatusBarStyle— so iOS falls back to.default/light-content.React Native's
StatusBarstack is not re-applied because it only calls the native module when_currentValuesdiffers from the merged stack result, and the stale_currentValueshides the discrepancy.✅ Current Workaround
Re-assert the style imperatively on every keyboard transition using
useKeyboardHandler:This works but is boilerplate every consumer has to add and shouldn't be necessary.
💡 Suggested Fix
After
attachToTopmostView()triggers a keyboard transition, callsetNeedsStatusBarAppearanceUpdate()on the app's root view controller to force iOS to re-querypreferredStatusBarStylefrom the correct (app) view controller rather than the keyboard window's.Alternatively, consider whether
attachToTopmostViewcan be done in a way that avoids triggering iOS's status bar re-evaluation.📋 Environment
react-native-keyboard-controller1.21.7(confirmed present on1.21.11)📸 Impact
Any app using
KeyboardControllerViewon a screen with a light theme anddark-contentstatus bar will see the status bar icons disappear while the keyboard is animating.