Notes

Styling the StatusBar in React Native, Expo and React Navigation

Edit on GitHub

React Native & Expo
3 minutes
  • StatusBar.currentHeight is Android only (e.g. 49.14285659790039 on Pixel 3 XL with a notch), return null on iOS
  • Constants.statusBarHeight from expo-constants works on both iOS and Android. (e.g. 20 on iPhone 5, 49 on Pixel 3 XL with a notch )
  • backgroundColor is also Android only
  • StatusBar needs to be outside of the SafeArea for it to render properly
  • SafeArea excludes the StatusBar. If you don’t use a SafeArea, the view will get inside the StatusBar
  • Set translucent on the status bar to make it behave consistently on iOS and Android. Doing so will make your life easier. Not doing so will means you’ll always add Platform specific code.

StatusBar height in iOS

The height is pretty much always 20, unless it’s hidden or an app is active during an incoming call, in which case it is 40 points. Except iPhone X and iPhone 11 are different because they have notches..

Drawing over and under

On iOS, your app will draw under the status bar. On Android, the app draws on top of the status bar. You can achieve similar behaviour for Android by setting translucent (Android only)

1<StatusBar translucent={true} backgroundColor={'transparent'} {...props} />

If we set translucent={true} on StatusBar then it’d behave consistently on both iOS and Adnroid, and you wouldn’t have to set different values for things like padding and height in a custom header using Platform checks

Coloring the StatusBar on iOS

Since backgroundColor is also Android only, you can not use it to set the background color for StatusBar in iOS.

What you can do instead is use the status bar inside a View that has padding at the top (equivalent to the height of status bar) and has a background color.

1<StatusBarBackground>
2  <StatusBar barStyle="light-content" />
3  <SafeAreaView>{/* Code goes here */}</SafeAreaView>
4</StatusBarBackground>
1import Constants from 'expo-constants'
2
3const headerHeight = 48
4
5const StatusBarBackground = styled.View`
6  background: salmon;
7  padding-top: ${Platform.OS === 'ios' ? Constants.statusBarHeight : 0}px;
8  height: ${Platform.OS === 'ios' ? Constants.statusBarHeight + headerHeight : headerHeight}px;
9`

Notice that you had to keep the padding and height Platform specific. Because on iOS the status bar draws under the status bar, we are only adding extra padding on iOS. On Android, we can pass backgroundColor to the <StatusBar>, and the default behaviour for the app is to draw over the status bar. This can be avoided if we set translucent={true} on StatusBar, and then it’d behave consistently on both iOS and Android. By default translucent is false on Android

1<StatusBarBackground>
2  <StatusBar translucent barStyle="light-content" />
3  <SafeAreaView>{/* Code goes here */}</SafeAreaView>
4</StatusBarBackground>
1import Constants from 'expo-constants'
2
3const headerHeight = 48
4
5const StatusBarBackground = styled.View`
6  background: salmon;
7  padding-top: ${Constants.statusBarHeight}px;
8  height: ${Constants.statusBarHeight + headerHeight}px;
9`

translucent with headerTransparent: true

1<StatusBar translucent barStyle="light-content" />

But this will give you issues with React Navigation if you use headerTransparent true for the default navigation header. You’ll have to manually add a margin top to avoid content flowing under the status bar

It appears that React Navigation default header doesn’t expect Android’s Status Bar to be translucent when you set headerTransparent to be true. When you do set headerTransparent: true, you also have to set headerForceInset: { vertical: 'never' } for it to not show any extra empty space, specially for nested headers.

1<StatusBar translucent={false} />
1// Translucent header, StatusBar should have translucent={false}
2headerTransparent: true,
3headerShown: true,
4headerForceInset: { vertical: 'never' }, // get rid of extra empty space at top
5headerStyle: { marginTop: Platform.OS === 'ios' ? Dimension.statusBarHeight : 0 },
1if (Platform.OS === 'android') {
2  // removes extra space at top of header on android
3  // SafeAreaView.setStatusBarHeight(0)
4}