React Native currently requires that UIViewControllerBasedStatusBarAppearance is set to NO. This is an app-global setting and Apple offers this to help bringing old (pre-iOS 7) apps over to newer OS versions. It's not recommended that this is set for new apps. The methods for manual status bar control are already deprecated and Apple explicitly discourages using them:
To opt out of the view controller-based status bar appearance behavior, you must add the UIViewControllerBasedStatusBarAppearance key with a value of false to your app’s Info.plist file, but doing so is not recommended.
https://developer.apple.com/reference/uikit/uiapplication/1622923-setstatusbarstyle#discussion
The check was added in 2015:
https://github.com/facebook/react-native/blame/64a4c6070df7e711e7fd01c490f369bbd0d0fb28/React/Modules/RCTStatusBarManager.m#L109-L111
At PSPDFKit we offer a React Native module. We also have a very similar check that warns if the value of UIViewControllerBasedStatusBarAppearance is still set to the old behavior.
https://pspdfkit.com/blog/2016/react-native-module/
Here's our FAQ article about it:
https://pspdfkit.com/guides/ios/current/faq/uiviewcontrollerbasedstatusbarappearance/
Other platforms (Xamarin) are switching to the new style as well:
https://github.com/xamarin/Xamarin.Forms/pull/463
See the code check for UIViewControllerBasedStatusBarAppearance. React should either support both or just default to the non-deprecated style. Currently any modification of the status bar requires this key to be set to false (true is the default)
This is tricky. See the related discussion on Twitter with Nick who wrote the original check:
https://twitter.com/nicklockwood/status/816334935422337025
I realize that React doesn't own the parent View Controller. There are still quite a few ways how the parent VC can be accessed and how hooks could be installed to both have the current flexibility (so we do not break any API) and offer compatibility with the new way of controlling the status bar.
I am willing to help and work on this but I'd first love to hear if there are any discussions around this that I missed while searching for it and what the mid- to long-term plans here are. I know that everything related to the status bar on iOS is painful, so I'm apologizing in advance for bringing up this issue.
@ide, this may be related to your team's work on exponent view for iOS. Maybe you can tag whoever has the most context
@ericvicenti We'd probably want to come up with whatever API makes sense for RCTRootView and then can expose a similarly structured API through ExponentView.
@steipete I haven't heard of any discussions about this since the original method works fine in most cases but I do think it's a good idea to be ready for when they finally do remove these APIs. There is a class called RCTRootViewDelegate that the programmer could hook up to the owning VC and we could add a method like reactRootViewDidRequestStatusBarStyleChange.
The tricky part is that an app can have multiple RCTRootViews per RCTBridge (the true core of React Native). I think the naive solution is for calls to StatusBar.setStyle(whatever) to be fed through the bridge to all RCTRootViews and up through each of their delegates, i.e. broadcast the status bar change to all owning VCs. I believe this would mostly match the semantics of the current API and globally change the status bar.
We probably do want to keep the deprecated API for now in case one of Facebook's apps uses it, if we break a FB app the commit is just going to be reverted.
StatusBar.setStyle
Didn't Apple introduce VC-based status bar control since global imperative calls to set the status bar state were too unwieldy? :) Maybe what we need is a RCTRootViewController for full-screen views and a declarative way to request a status bar appearance in JS where it's clear what takes precedence in the case of a conflict.
We still need an imperative way to change the status bar style for the current VC, whether that's an RCTRootViewController or just any UIViewController that conforms to RCTRootViewDelegate. I prefer the latter to keep the API surface area of RN more flexible.
Most RN apps are housed under one RCTRootView (and therefore one VC) so we do need a way to request status bar changes. They have to be imperative at the Obj-C level I think because all bridge calls are imperative. Navigation libraries can then wrap the imperative call in a declarative API in user space.
Yep, at some point every API needs to be imperative. I never really understood why we decided to make a status bar component- because the behavior can be totally unexpected when there are multiple StatusBar components in the hierarchy but only one global status bar to control. I think it is a pretty safe bet to treat a app-global API like a global API for our JS app.
@ericvicenti I agree, I find the current StatusBar component short-sighted. Thinking about tab bars and drawers and other navigation paradigms, there are many cases where there are two scene components mounted on-screen at the same time and you can toggle between which one is "active". React has no notion of the "active" screen but the navigation API does -> react-navigation is the right level of abstraction to expose a status bar component or prop.
React has no notion of the "active" screen but the navigation API does -> react-navigation is the right level of abstraction to expose a status bar component or prop.
Totally agree!
I have the exact same gripes with the <Modal> component
Well, it would be nice long-term if we can clearly delineate which are best avoided in structured applications – or else people will surely use the imperative one even when they should be using a navigation-based one. You know how people are…
Any news on that?
Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!
If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.
@hramos This is a conceptual issue and I have not seen a fix for it yet - please re-open this ticket.
I've applied the "For Discussion" label, which should prevent this issue from getting closed in the future due to inactivity.
We've got another ping from a customer that uses RCTStatusBarManager which requires UIViewControllerBasedStatusBarAppearance to be set to NO. Are there any plans to convert RCTStatusBarManager to work with the root view controller? If RN is all view-based, shouldn't that be relatively easy to convert (forgive me my ignorance if I got that wrong)
I agree that react native should at least support both modes, its the direction apple seems to recommend. There are plugins that expect this setting to be YES, and throw an error when it is set to NO like RN likes. I have upgraded to all the latest versions and still see the issue. I'm not all that familiar with the inner workings of what this change implies, but clearly its worth someone proposing a backward compatible "fix" rather than just parking this as a discussion topic.
Here's another plugin that requires UIViewControllerBasedStatusBarAppearance to be set to YES.
https://github.com/underscopeio/react-native-facebook-account-kit/issues/21
react-native-navigation supports both modes:
https://github.com/wix/react-native-navigation/blob/master/ios/RCCViewController.m
Is nobody else running into this issue?
@steipete I'm running into this issue with a combination of react-native-navigation and storybook
The problem being that we're using UIViewControllerBasedStatusBarAppearance YES in the actual app (supported by react-native-navigation), but then storybook won't run.
Dunno how much help this is...guess this is just a wordy "+1" 😅
@steipete I'm getting this error too.
I don't know if you know, but as long you put the value to YES and remove anything calling StatusBar the error disappear. Don't forget the libraries :)
Not a solution but...
@Ragnar-H, did you come up with a work-around? I'm running into the same issue (rnn + storybook).
In the short term I'd love a suggestion to suppress this error:

I have tried componentDidCatch in the parent component that is rendering the Storybook root component (which I presume is causing the error), but that does not seem to work. Perhaps since the error is happening in the native code?
@derrh @Ragnar-H
In Storybook on page "storybook/app/react-native/src/preview/components/OnDeviceUI/index.js" it's calling the StatusBar component from react-native.
import { Dimensions, View, TouchableWithoutFeedback, Image, Text, StatusBar } from 'react-native';
You can solve your problem by removing the import of statusBar on that page.
I advise you to create a fork and maintain or ask to remove the need for statusBar.
I don't understand why some libraries insist on taking care of statusBar, the only person who should change the statusBar should be the developer.
I don't understand why some libraries insist on taking care of statusBar, the only person who should change the statusBar should be the developer.
On iOS, the status bar should always match the topmost view controller, and Apple recognized and changed this behavior in iOS 7. deprecating the previous behavior, which basically were global toggles that any could could call at any time - which often was very challenging when view controllers pushed that to store the status bar style and then reset it.
Since React Native doesn't use the view controller concept and simply manages views, it makes sense to have such a status bar manager. There's still one rootViewController, and it should be possible to make this root controller manage and forward the status bar management, so React apps can move over to the modern status bar management without any functional regressions. (I am not that deep in React to verify this, potentially it's enough to add that to https://github.com/facebook/react-native/blob/master/React/Views/RCTWrapperViewController.m)
@steipete I'm not saying that a framework like react-native shouldn't have control over statusBar.
I'm saying that packages like react-native-elements and storybook, shouldn't call the statusBar component from react-native. The only person to dictate the statusBar should be the developer and not be forced by some component package.
But hey this is just my two cents :)
Sorry if this is derailing the main discussion of this issue.
@derrh we turned off onDeviceUI for our use case.
Look for getStorybookUI and set to false:
const StorybookUIRoot = getStorybookUI({ port: 7007, onDeviceUI: false });
@steipete, this is one of the big impedance mismatches with react-native on iOS. Much of the API for UIKit is in UIViewController et al. It is not safe to assume that all users of React Native will always have a single RCTWrapperViewController. Apps using wix/react-native-navigation or embedding RCTViews in their own view controller will have none.
@FlaviooLima, I agree. React Native libraries should not touch the StatusBar api. I'll fork storybook and work with them to remedy. Sorry for derailing.
@Ragnar-H, thanks! onDeviceUI: false solved the issue for my immediate use case.
One possible solution would be to use the modern non-deprecated API for status bar appearance and have the StatusBar api interface with RCTWrapperViewController which would need to be updated to adopt the status bar appearance API. This would allow consistent behavior for users who are doing a typical React Native app, but also prevent errors for those who are embedding RN in their custom view controllers or using a 3rd party nav solution such as wix/rnn.
I am not sure but I believe most people using React Native don't go through RCTWrapperViewController which makes this a more complex conversation than just fixing the status bar API unfortunately. :( I know this is an awkward mismatch but it doesn't seem like it is easy to rectify.
What is the suggested way to deal with view controllers from third-party SDKs that want to set their own status bar style?
For example, I don't use the StatusBar module anywhere in my app, but if I set UIViewControllerBasedStatusBarAppearance to YES I get the error mentioned above. I guess some third party module tries to use StatusBar.
If I want to use let's say the Facebook Login SDK, it shows its own view controller (for login) with a light navigation bar, t looks bad when the status bar style is also set to light.
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.
As far as I know, this is still an unsolved conceptual issue!
This issue is still unsolved. React Native needs to move to view controller based status bar management to be compatible with 3rd-party SDKs.
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
This issue has been moved to react-native-community/react-native-statusbar#5.
Most helpful comment
Is nobody else running into this issue?