Customizing the Header
The native stack navigator renders a header bar at the top of each screen by default. You can customize everything about it — the title text, background color, button placement, and even replace it entirely. All customization goes through the options prop on Stack.Screen or screenOptions on Stack.Navigator.
Setting the Title
The simplest customization is changing the title text:
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{ title: 'Item Details' }}
/>
The name prop is used for navigation (navigate('Details')), while title controls what appears in the header. Without a title, the header shows the screen name.
Dynamic Titles from Params
You can set the title based on route params by passing a function to options:
<Stack.Screen
name="Details"
component={DetailsScreen}
options={({ route }) => ({ title: route.params.title })}
/>
Now the header shows whatever title param was passed during navigation.
Styling the Header
Control colors and text styles through screenOptions on the navigator (applies to all screens) or options on individual screens:
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#6200ee' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' },
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
headerStyle— styles the header container. UsebackgroundColorto change the bar color.headerTintColor— sets the color of the title text, back button, and header icons.headerTitleStyle— additional text styles for the title.
Adding Header Buttons
Use headerRight or headerLeft to place buttons in the header:
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerRight: () => (
<Button title="Info" onPress={() => alert('Info pressed')} />
),
}}
/>
For buttons that need access to navigation, use the function form of options:
<Stack.Screen
name="Home"
component={HomeScreen}
options={({ navigation }) => ({
headerRight: () => (
<Button
title="Settings"
onPress={() => navigation.navigate('Settings')}
/>
),
})}
/>
Setting Options from Inside a Screen
Sometimes you need to set header options from within the screen component itself — for example, after loading data. Use navigation.setOptions:
function DetailsScreen({ navigation, route }) {
React.useEffect(() => {
navigation.setOptions({ title: route.params.title });
}, [navigation, route.params.title]);
return (
<View style={styles.container}>
<Text>{route.params.title}</Text>
</View>
);
}
Hiding the Header
To hide the header on a specific screen:
<Stack.Screen
name="Fullscreen"
component={FullscreenScreen}
options={{ headerShown: false }}
/>
To hide it for all screens in a navigator, use screenOptions={{ headerShown: false }} on the navigator.
Complete Example
Here's a stack with a styled header, dynamic title, and a settings button:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { View, Text, Button, StyleSheet } from 'react-native';
const Stack = createNativeStackNavigator();
function HomeScreen({ navigation }) {
return (
<View style={styles.container}>
<Text style={styles.title}>Home</Text>
<Button
title="View Profile"
onPress={() => navigation.navigate('Profile', { name: 'Jason' })}
/>
</View>
);
}
function ProfileScreen({ route }) {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello, {route.params.name}</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Settings</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
title: { fontSize: 24 },
});
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerStyle: { backgroundColor: '#6200ee' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' },
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={({ navigation }) => ({
title: 'My App',
headerRight: () => (
<Button
title="⚙️"
color="#fff"
onPress={() => navigation.navigate('Settings')}
/>
),
})}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={({ route }) => ({ title: route.params.name })}
/>
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
The header is purple across all screens, shows "My App" on the home screen with a settings button, and displays the user's name on the profile screen. All of this is declarative — no imperative header manipulation needed.
That covers headers. Try experimenting with headerRight, headerStyle, and setOptions in your own project — most apps need all three.