Providing a light theme and a dark theme is a nice way to let your users adjust the appearance of your app depending on the time of day or their preference. It also signals that you are a hip app developer that keeps up with the trends of the day.
Note: support for built-in themes requires [email protected]>=3.12.0!
As operating systems add built-in support for light and dark modes, supporting dark mode is less about keeping hip to trends and more about conforming to the average user expectations for how apps should work. In order to provide support for light and dark mode in a way that is reasonably consistent with the OS defaults, these themes are built in to React Navigation. You can pass in a
theme prop to your app container component in order to switch between light and dark mode, and the value of that
theme prop can come from whichever API you use to detect user preferences for dark mode, or in the case of older operating system versions, from a custom configuration within your app UI.
This will take care of styling the stack navigator, bottom tab navigator, and drawer navigator for you. React Navigation also provides several tools to help you make your customizations of those navigators and the screens within the navigators support both themes too.
Using the operating system preferences
At the time of writing,
react-native does not currently support detecting the operating system color scheme preferences in the core (you can follow this pull request). Until it is part of core and you have updated to the version that includes it, you can use
You will need iOS 13 to actually be able to toggle dark mode through system settings.
Note: if you use the Expo managed workflow, this requires SDK 35+
First, you need to install
react-native-appearance. Follow the instructions in the README.
Once you've installed it, set your root component up as follows:
If the version of React Native you are using doesn't support hooks yet, you can use the
Appearance.getColorScheme() functions as described in the usage section of the README.
See a full working example of theme integration in react-navigation/theme-example.
Using the currently selected theme
Two tools are available to gain access to the theme in any component that descends from the app navigation container:
useTheme is a simple custom hook that returns the theme.
ThemeContext lets you access the theme using the
ThemeContext.Consumer pattern or with
Using default theme colors
There is a small but perhaps useful list of colors that are used to style navigators according to the theme. This list of colors is exported under
ThemeColors. See the TypeScript definition for a full list of colors.
Default themed components
Several components have defaults that are biased to a specific theme.
Text, for example, defaults to black.
StatusBar defaults to dark text. React Navigation provides themed alternatives to these.
Built-in themes inside
Built-in themes inside static navigator configuration
Colors that are specified within the static configuration options for a navigator can now be specified as objects with
The old format still works too, but colors specified in the following way will not adapt to themes:
Custom themes using React context
You may want more control than what you're given with just the built-in themes. In this case, you can build your own themes entirely from scratch.
Building custom themes into an app with React Navigation is not too much different than a React app without it; the main differences are that you will need to use
screenProps in order to update style properties controlled by
navigationOptions, and when style properties are controlled in navigator configuration we'll need to take another approach. First we're going to recap how you would theme a React app without React Navigation, then we will dive deeper into these differences. Additionally, this guide assumes that you are already comfortable with React Navigation, in particular how to use and configure navigators.
React's context API allows you to share state from an ancestor component to any of its descendants without explicitly passing the value through layers and layers of components ("prop drilling"). This is a useful tool in order to build themes because we can define the theme at the root of the app, and then access it from anywhere else and re-render every themed component whenever the theme changes. If you are not familiar with how to use context already, you might want to read the React documentation for it before continuing.
Okay, that's a lot of code. There isn't much going on here aside from passing the theme around through context and then pulling it out of context when we need it inside of themed component. Themed components like
ThemedButton are useful to help you avoid constantly repeating theme context related boilerplate.
A regrettable limitation of the current implementation of
navigationOptions is that we are unable to access React context for use in properties such as
headerTintColor. We can and should use them in properties that access React components, for example in
headerRight we could provide a component like
ThemedHeaderButton. To apply the theme to other properties we need to use
Success! The stack header style now updates when the theme changes.
Note: in the future we would like to deprecate
screenPropsand move entirely over to React context. For now,
screenPropsis the best way to do that, and when this changes it will be easy to migrate.
Theming tabs and other similar navigators
Some navigators may have their styles configured in the navigator configuration object when they are initialized. While it may be best to update these navigators so that they can be configured more easily through
navigationOptions, as long as they allow us to override the UI that they render with our own component and give us access to the default component, we can work with them just fine. We'll look at how to theme a bottom tab navigator.
You will likely want to go a bit further than we detailed in this guide, such as change the status bar color depending on the theme and customize the border color for the header and tab bar as well. You can see all of the above code plus some more changes to make it more complete in this Snack.
I never said it was easy, but this about covers what you need to know to be able to theme an app that uses React Navigation. Good luck, remember me when you're a billionaire.