Modern applications need to support multiple color modes, including an easy switch between light and dark mode. This article is the complete guide to creating color modes in
React Native
apps with toggle features.What we will cover ⤵️
- How to set the initial color mode
- System-based color mode
- Getting system color mode using React Native
- Getting color mode using NativeBase
- Hooks and pseudo props to achieve color mode
- Toggling color mode
- Demo till now
- Persisting color mode
How to set the initial color mode
👉 You can extend the default theme with
config
in NativeBaseProvider
. The default color mode is light
. 👉 To set the initial color mode, pass
initialColorMode
in the config
object. It will take the values assigned for light
and dark
. The initial color mode of the app will be the one passed as initialColorMode
.import React from "react";
import { NativeBaseProvider, extendTheme } from "native-base";
export function App({ children }) {
const config = {
initialColorMode: "dark", // initial color mode
}
const extendedTheme = extendTheme({ config })
return (
<NativeBaseProvider theme={extendedTheme} >
{children}
</NativeBaseProvider>
)
}
System-based color mode
👉 The
useSystemColorMode
prop sets the app's color mode based on the system. It uses the boolean value.👉 If
useSystemColorMode
is true, then the initial color mode will be the system color mode. Else, it will be light
mode.import React from "react";
import { NativeBaseProvider, extendTheme } from "native-base";
export function App({ children }) {
const config = {
useSystemColorMode: true, // Default system color mode
}
const extendedTheme = extendTheme({ config })
return (
<NativeBaseProvider theme={extendedTheme} >
{children}
</NativeBaseProvider>
)
}
Getting system color mode using React Native
👉 The Appearance module provides information about the user's appearance preferences.
👉 You can get the desired color scheme using
getColorScheme
.import { Appearance } from 'react-native';
const colorScheme = Appearance.getColorScheme();
console.log(colorScheme, 'color-scheme');
if (colorScheme === 'dark') {
// Use dark color scheme
}
Getting color mode using NativeBase
👉 NativeBase provides a hook to get the desired color mode.
const { colorMode } = useColorMode(); // light or dark
👉 The applied scheme will be
light
or dark
based on the current color mode.Hooks and pseudo props for color mode
👉 NativeBase provides the following props to get the format you want.
useColorMode
useColorModeValue
_light
_dark
We’ve explained what they are below ⤵️
useColorMode
This hook provides access to the current
colorMode
of the app and toggleColorMode
.const Example = () => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Center
flex={1}
bg={colorMode === "light" ? "coolGray.50" : "coolGray.800"}
>
<Heading color={colorMode === "light" ? "coolGray.800" : "coolGray.50"}>
{`Color mode is toggled to ${colorMode}.`}
</Heading>
<Pressable mt="10" onPress={toggleColorMode}>
{colorMode === "light" ? (
<MoonIcon color="coolGray.800" size="6" />
) : (
<SunIcon color="coolGray.50" size="6" />
)}
</Pressable>
</Center>
);
};
👉 In the above snippet,
colorMode
will be light
or dark
based on the current color mode. You can use the toggleColorMode
function anywhere in the app to switch between the two modes. useColorModeValue
This hook takes two arguments: values in
light
and values in dark
.const Example = () => {
const { colorMode, toggleColorMode } = useColorMode()
const bg = useColorModeValue('coolGray.50', 'coolGray.800')
const color = useColorModeValue('coolGray.800', 'coolGray.50')
const icon = useColorModeValue(
<MoonIcon color="coolGray.800" size="6" />,
<SunIcon color="coolGray.50" size="6" />
)
return (
<Center flex={1} bg={bg}>
<Heading color={color}>
{`Color mode is toggled to ${colorMode}.`}
</Heading>
<Pressable mt="10" onPress={toggleColorMode}>
{icon}
</Pressable>
</Center>
)
}
👉 In the above snippet,
useColorModeValue
hook is taking light
and dark
mode values respectively._light
& _dark
👉 Styles passed in
_light
& _dark
will be applied in their respective modes.import React from 'react';
import { Icon, useColorMode, Pressable, Center, Heading } from 'native-base';
import { Feather } from '@expo/vector-icons';
export const Example = () => {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Center
flex={1}
w="full"
_light={{ bg: 'coolGray.50' }}
_dark={{ bg: 'coolGray.800' }}
>
<Heading
_light={{ color: 'coolGray.800' }}
_dark={{ color: 'coolGray.50' }}
>
{`Color mode is toggled to ${colorMode}.`}
</Heading>
<Pressable mt="10" onPress={toggleColorMode}>
<Icon as={Feather} _light={{ name: 'moon' }} _dark={{ name: 'sun' }} />
</Pressable>
</Center>
);
};
By default, NativeBase components are dark mode enabled.
Note: It’s recommended to use _light and _dark props, if you want to use useColorModeValue
hook, you can use it at top of the component.
Toggling color modes
👉 You can use
useColorMode
hook for toggling. It provides a toggleColorMode
function that can be used to switch between the two modes. const { toggleColorMode } = useColorMode();
🎉 And that’s how we use different color modes and toggle between them using NativeBase.
Summary and Demo
👉 It’s time to see everything in action. To access the source code of the demo CLICK HERE. 🎉🎉
👉 In the above demo code, the initial mode will be the system color mode.
👉 The
useColorMode
hooks get the current color mode and toggle color mode.👉
_light
and _
dark
pseudo props apply to style based on color mode.But what about color mode persistence? 🤔🤔
Here is how to use them for native and web.
Persisting color mode
👉 You can keep a color mode persistent by defining
colorModeManager
of type StorageManager
in NativeBaseProvider
. This will retain color mode even if the page is refreshed.For Native
👉 Use react-native-async-storage in native apps. It is asynchronous and a key-value storage for React Native applications.
import React from 'react';
import { NativeBaseProvider, StorageManager, ColorMode } from 'native-base';
import AsyncStorage from '@react-native-async-storage/async-storage';
const colorModeManager: StorageManager = {
get: async () => {
try {
let val = await AsyncStorage.getItem('@color-mode');
return val === 'dark' ? 'dark' : 'light';
} catch (e) {
return 'light';
}
},
set: async (value: ColorMode) => {
try {
await AsyncStorage.setItem('@color-mode', value);
} catch (e) {
console.log(e);
}
},
};
export default function () {
return (
// pass it to NativeBaseProvider
<NativeBaseProvider colorModeManager={colorModeManager}>
{children}
</NativeBaseProvider>
);
}
For web
👉 Use localStorage to store color mode in the web browser. It is a read-only property of the window interface. This provides access to a storage object for the document's origin. The data stored is saved across browser sessions.
import React from 'react';
import { ColorMode, NativeBaseProvider, StorageManager } from 'native-base';
const colorModeManager: StorageManager = {
get: async () => {
let val = localStorage.getItem('@color-mode');
return val === 'dark' ? 'dark' : 'light';
},
set: async (value: ColorMode) => {
let strValue = value ? value.toString() : '';
localStorage.setItem('@color-mode', strValue);
},
};
export default function () {
return (
<NativeBaseProvider colorModeManager={colorModeManager}>
{children}
</NativeBaseProvider>
);
}
If you want to explore more, here are some examples of applications that were built using NativeBase. Check them out here 🔗 https://madewithnativebase.com/
Till next time then, ciao! 👋🏻