Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
This turned into a massive adventure and subsequently, a very large and messy post, so to spare you from having to read through the mess that I keyboard-farted out below, here's a summary:
Main goal
: To find a way to selectively show the navigation bar in my app without also selectively removing the Safe area padding to prevent my content being clipped by the iPhone X notch.
Why I did it the way I did
: I wanted to try and use the Navigation Bar's built-in safe area padding instead of react-native's
<SafeAreaView>
because the
<SafeAreaView>
would interfere with the built in padding and cause the headers to be unnecessarily tall.
Side effect of not doing it the standard way
: There was a faint line between the header (shown in picture with
height: 0
) and content that was plainly visible when both header and content were the same color
What I tried
:
Using
<SafeAreaView>
Not using
<SafeAreaView>
and trying to
header: null
instead (aka "the recommended way of doing it")
Playing with header options to make the header disappear without causing clipped content. As a side affect (quoted from extended post below)
i also found that
header: null
is functionally the same in result as
headerTransparent: 'true'
which I later discovered, is also
functionally the same result as
display: 'none'
. All seem to be
valid ways of making the entire header, Safe area padding and all,
disappear.
Playing with the
borderColor
and
borderWidth
to determine if it was a border (in hindsight i should have done this more thoroughly)
Playing with 'opacity'
Shifting both the header and content around with
position: 'relative', top: 6
Re-creating the issue in Xcode to see if it was an iOS issue (hindsight: i did this wrong)
This leads pretty cleanly into the answer so i'll cut it off here and continue it in my answer.
The long, confusing, original version
I'm using react-navigation in my react-native project (created with CRNA) and I think I have found a way to style the headers of a
StackNavigator
so that iOS takes care of the safe areas for you and negates the need to use
<SafeAreaView>
(which was interfering with the header on other screens).
My app is arranged such that the first screen is sort of like a home screen with a grid of buttons which will eventually each have their own page in the
StackNavigator
. On this home screen I want to disable the header bar since there is nothing to navigate to and it just moves the content down, however, on the other screens, I want to have the header bar visible to display the back button. While using
<SafeAreaView>
I could only get one of the two mentioned above, either the home screen was clipped by the notch on the iPhone X, or the
<SafeAreaView>
moved the navigation/header bar on the other screens down and takes up space.
However, I found that by ditching the
<SafeAreaView>
entirely, i was able to re-create what I wanted using header styling from react-navigation:
App.js
const Navigation = createStackNavigator({
Home: HomeScreen,
Test: PageScreen,
headerMode: 'screen',
navigationOptions: {
headerStyle: { backgroundColor: colors.background},
headerTintColor: colors.headerTint,
headerTitleStyle: {
fontWeight: 'bold',
HomeScreen.js
static navigationOptions = {
headerStyle: {
height: 0,
backgroundColor: colors.background //had to re-color it here too because otherwise the header would be white???
This works well because it effectively removes the header from the home screen but still keeps the safe area padding that the header creates. However, there is a thin line now separating the header from the Home Screen content and i'm not sure how to make it go away. It is the only thing that gives away my header trickery and detracts from the user experience.
Here is what I'm talking about:
This does not affect the other screens in which i want the header visible: Apparently it actually does, the colors were just masking it...
This line also appears on my iPhone 8 while testing the app using expo, although it is not as far down due to the smaller status bar on that device.
I have already tried changing the headerTintColor
in the navigationOptions
because I thought there may be some kind of background color behind the one I set but apparently that controls the color of the text and back button. The internet also doesnt seem to have much on this from what I can immediately tell as searches for header line react-navigation
come up with results about hiding the header, being unable to hide the header, and how to customize the header. Does anyone know what this line is and how I remove it? or failing that, how to make <SafeAreaView>
play nice with a StackNavigator
's navigation header?
EDIT: I have also already tried the header: null,
solution, however, by removing the header on the homepage of the app and not others causes a weird side effect with the <SafeAreaView>
where the <SafeAreaView>
's safe area adds onto the one already built into the iOS header, causing the header to be a lot larger than it should, which is why I opted to go for height: 0
instead, since it renders the header effectively invisible, yet still keeps it's safe area.
EDIT 2: after playing with the borderColor
and borderWidth
of the header, I have determined that this line is not a border...
headerStyle: {
height: 400,
backgroundColor: 'green',
borderColor: 'red',
borderWidth: 150,
EDIT 3: more findings. After playing with the CSS I have found that setting the opacity: 0
reveals a white layer behind the navigation bar... maybe this is slightly bigger than the navbar itself?
also, it seems like header: null
is functionally the same in result as headerTransparent: 'true'
which I later discovered, is also functionally the same result as display: 'none'
. All seem to be valid ways of making the entire header, Safe area padding and all, disappear.
shifting it with position: 'relative', top: 6
seems to not solve the issue either
EDIT 4:
Since I have determined that this line was in fact not just appearing on the screen where i'd set the header height to 0 and instead was appearing on all screens, I think this is something that is intentionally built into iOS in order to differentiate the header from the page content.
EDIT 4a: to confirm this theory I created a native-only xcode project and tried to recreate this by setting the nav bar and the view to black and, in contrary to my expectations, the issue did not re-create itself. So this is indeed something created by react-native and not built-into iOS i stand corrected again... How to remove navigation bar border/shadow?
–
–
–
–
–
Continued from summary at the start of the question...
Once I realized my Xcode test was flawed i started googling for iOS only posts on StackOverflow with the same issue:
How to remove navigation bar border/shadow?
How to hide UINavigationBar 1px bottom line
Since these were iOS native solutions only I started looking for ways to re-create them in react. This then led me to looking for the same iOS only problem but with react keywords when I found the solution:
How do I hide the shadow under react-navigation headers?
While this question seems to be targeted at android, the answers also mention iOS:
elevation: 0, // remove shadow on Android
shadowOpacity: 0, // remove shadow on iOS
Source: https://stackoverflow.com/a/42709731
I tried this. It didnt work.
Then further down an answer said this:
headerStyle: {
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0,
Tried it: It worked.
TL;DR
If you want to hide the header while using a StackNavigator
in modern versions of react native without having to use a <SafeAreaView>
, use the following code either in createStackNavigator({...})
or in your Screen classes' static navigationOptions = {...}
:
headerStyle: {
backgroundColor: colors.background,
borderBottomWidth: 0,
height: 0,
In navigation v5, in your stack screen add in your options object:
<Stack.Screen
name="Whatever"
component={SomeScreen}
options={{
title: "Whatever",
headerTitleStyle: { fontSize: 22, color: "#fff" },
headerStyle: { shadowColor: "transparent" } // This is the important bit
// whatever else you need in the screen header
UPDATE V6:
since released React Navigation V6, you can't hide header shadow using headerStyle option. instead of that you can use bolean option headerShadowVisible and set it to be false like example bellow:
<Stack.Screen
name="Example"
component={ExampleComponent}
options={{headerShadowVisible: false}}
Use { elevation: 0 }
as a headerStyle
screen-option. I confirmed this works in React Navigation V5. I think this (or similar) may work in React Navigation V4 as well.
<Stack.Navigator
screenOptions={{
headerStyle: { elevation: 0 }
<Stack.Screen
name="Home"
component={HomeScreen}
</Stack.Navigator>
As an update for v5, what worked for me was headerHideShadow: true
.
So in context:
<LibraryStack.Navigator
screenOptions={{
headerHideShadow: true
Update:
This is only for the native-stack
(i.e. 'createNativeStackNavigator'). Leaving this behind in case someone using the native-stack
still lands on this question.
More information (both for native-stack
and stack
):
https://github.com/react-navigation/react-navigation/issues/6899
–
–
–
I know this is an old question with an accepted answer, but I wanted to add a little clarity because it tripped me up. If you have nested Navigator
s you need to make sure you put the screenOptions
on the correct one in order to see the changes.
My set up was:
<NavigationContainer>
<Stack.Navigator>
{isLoading ? (
// We haven't finished checking for the token yet
<Stack.Screen name='Splash' component={SplashScreen} />
) : userToken == null ? (
// No token found, user isn't signed in
<Stack.Screen
name='SignIn'
component={SignInScreen}
options={{
// When logging out, a pop animation feels intuitive
animationTypeForReplace: isSignout ? 'pop' : 'push',
title: 'Sign in',
// headerStyle: {
// backgroundColor: theme.secondaryBackground,
// },
headerShown: false,
) : (
// User is signed in
<Stack.Screen name='Homie' component={AuthenticatedAppNavigator} />
</Stack.Navigator>
</NavigationContainer>
I was trying to set the options on the AuthenticatedAppNavigator
component which is a nested navigator. The border was hidden once I moved the options to the parent navigator like below:
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerStyle: {
shadowOpacity: 0,
elevation: 0,
{isLoading ? (
// We haven't finished checking for the token yet
<Stack.Screen name='Splash' component={SplashScreen} />
) : userToken == null ? (
// No token found, user isn't signed in
<Stack.Screen
name='SignIn'
component={SignInScreen}
options={{
// When logging out, a pop animation feels intuitive
animationTypeForReplace: isSignout ? 'pop' : 'push',
title: 'Sign in',
// headerStyle: {
// backgroundColor: theme.secondaryBackground,
// },
headerShown: false,
) : (
// User is signed in
<Stack.Screen name='Homie' component={AuthenticatedAppNavigator} />
</Stack.Navigator>
</NavigationContainer>
Also, the elevation
property only applies to Android, so shadowOpacity
is needed for iOS.
Work for me on "@react-navigation/native-stack": "^6.1.0"
static screenOptions = {
headerShadowVisible: false
I'm a little confused...Are you trying to hide the header?
If so simply set header to null.
HomeScreen.js
static navigationOptions = {
header: null
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.