Choosing Header Configuration Options in React Navigation screenOptions
Learn how to use React Navigation's screenOptions API to set header titles, buttons, and styles across stack and tab navigators, compare the available options, and see a TypeScript‑safe implementation you can verify on iOS and Android.
28 Jan 2026, 04:50 UTC

Decision: Use screenOptions for consistent header configuration
Problem: You want every screen in a navigator to share the same header title, buttons, and styling without repeating the same props on each route definition.
Useful takeaway: Define screenOptions once on the navigator; individual screens can still override specific keys when needed.
Constraints
- Support both stack and bottom/top tab navigators.
- Keep TypeScript autocomplete and type safety.
- Verify behavior on iOS and Android.
Supported screenOptions compared
| Option | What it controls | Applicable navigator(s) | Notes |
|---|---|---|---|
headerTitle |
Text or component shown in the header centre. | Stack | Can be a string or React element. |
headerRight / headerLeft |
Buttons or components on the right/left side. | Stack | Receive navigation props. |
headerStyle |
Background colour, height, elevation, etc. | Stack | Passed to the header container. |
headerTintColor |
Colour for header icons and title text. | Stack | May be ignored on some older versions; verify. |
headerTitleStyle |
Font size, weight, colour of the title. | Stack | Overrides headerTintColor for title only. |
headerBackTitleVisible |
Show previous screen’s title on back button. | Stack | Boolean; default true on iOS, false on Android. |
tabBarIcon |
Icon displayed in the tab bar. | BottomTab, TopTab | Receives focused, color, size. |
tabBarLabel |
Text label under the icon. | BottomTab, TopTab | Can be undefined to show only icon. |
tabBarStyle |
Background colour, height, border of the tab bar. | BottomTab, TopTab | Similar to headerStyle but for tabs. |
headerShown |
Hide the header entirely for a screen. | Stack | Useful for modal or full‑screen screens. |
Trade‑offs
- Global vs per‑screen: Setting screenOptions at the navigator level reduces boilerplate; overriding on a single screen requires adding the option to that screen’s options object.
- Navigator specificity: Header‑related keys only affect stack navigators; tab‑related keys do not influence header appearance.
- Performance: Options are read once when a route mounts; runtime impact is negligible.
- Platform quirks: Some properties (e.g.,
headerTintColor) may be ignored on certain React Navigation versions or when using custom header components.
Concrete implementation (TypeScript)
The example below creates a root stack that contains a tab navigator. Header options are defined on the stack, while tab‑specific options are defined on the tab navigator.
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { ReactNode } from 'react';
import { View, Text, Platform, StyleSheet } from 'react-native';
type RootStackParamList = {
Home: undefined;
Settings: undefined;
};
type TabParamList = {
Feed: undefined;
Profile: undefined;
};
const Stack = createStackNavigator<RootStackParamList>();
const Tab = createBottomTabNavigator<TabParamList>();
function HomeScreen() {
return (
Home screen
);
}
function SettingsScreen() {
return (
Settings screen
);
}
function FeedScreen() {
return (
Feed screen
);
}
function ProfileScreen() {
return (
Profile screen
);
}
// Tab navigator with its own screenOptions
function AppTabs() {
return (
(
{/* Replace with your actual icon library */}
{focused ? '●' : '○'}
),
tabBarLabel: ({ focused }) => (focused ? 'Label' : undefined),
tabBarStyle: {
backgroundColor: Platform.select({ ios: '#f8f8f8', android: '#fff' }),
height: 56,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: '#ddd',
},
})}
>
);
}
// Root stack navigator with header screenOptions
export default function App() {
return (
(
Info
),
headerStyle: {
backgroundColor: Platform.select({ ios: '#0066ff', android: '#0066ff' }),
height: Platform.select({ ios: 44, android: 56 }),
elevation: 0, // remove Android shadow if desired
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: '600',
fontSize: Platform.select({ ios: 17, android: 18 }),
},
headerBackTitleVisible: false,
// Hide header on modal screens if needed
headerShown: true,
}
>
{/* The tab navigator lives inside a stack screen so it inherits the header */}
);
}
Verification steps
- Run the app on an iOS simulator or device:
npx react-native run-ios(or use Expo). - Run on Android:
npx react-native run-android. - Visually confirm that each screen shows the header title “My App”, the right‑hand “Info” button, and the correct background colour.
- Open the tab navigator (“Tabs” screen) and verify that the tab bar shows the icons and labels as defined, while the header remains unchanged.
- In your IDE, place the cursor on any screenOption key (e.g.,
headerTintColor) and ensure autocomplete suggests the correct TypeScript type from@react-navigation/native. - If you change
headerTintColorto a different value and rebuild, the header text and icons should update accordingly.
Limitations and practical checks
- Header‑related options are ignored when a screen uses a custom header component via
headerprop; in that case you must style the custom component directly. - On React Navigation versions prior to 5.x,
headerTintColorhad no effect on Android; verify your package version (npm list @react-navigation/native). - Tab navigators do not render a header by default; if you need a header inside a tab, wrap the tab navigator in a stack screen as shown.
- To check that an option is truly applied, inspect the rendered native header (e.g., using Flipper or Android Studio’s Layout Inspector) and compare the observed properties with the values you set.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.