How to Detect User Color Preference in React Native
Tags: reactnative, typescript, styling
Published: 2022-06-20 18:13:41

---
title: How to Detect User Color Preference in React Native
published: true
description: Learn to manage multiple color schemes in your React Native app using the core useColorScheme hook.
tags: reactnative, typescript, styling
over_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/956n6a6cg8sosan9oy64.jpg
# Use a ratio of 100:42 for best results.
canonical_url: https://www.reactnativeschool.com/how-to-detect-user-color-preference-in-react-native
---

React Native has two ways for you to determine a user's appearance preferences:

- The [Appearance](https://reactnative.dev/docs/appearance) API which lets you get their current color scheme
- The [useColorScheme](https://reactnative.dev/docs/usecolorscheme) hook which provides an up-to-date color scheme (it will automatically update as the user's preferences change)

_This post was originally [posted on React Native School](https://www.reactnativeschool.com/how-to-detect-user-color-preference-in-react-native). Visit React Native School to access 170+  tutorials and 18 courses!_

Today we'll be leveraging the `useColorScheme` hook.

We'll take a look at the following screen which shows black text and a white background - a light color scheme.

```tsx
import React from "react"
import { View, Text, ViewStyle, TextStyle, StyleSheet } from "react-native"

const App = () => {
  const viewStyles: ViewStyle[] = [
    styles.container,
    { backgroundColor: "white" },
  ]
  const textStyles: TextStyle[] = [styles.text, { color: "black" }]

  return (
    <View style={viewStyles}>
      <Text style={textStyles}>Hello, world!</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
})

export default App
```

We can use the `useColorScheme` hook and determine the user's preferred color scheme, changing our colors based on it.

```tsx
import React from "react"
import {
  View,
  Text,
  ViewStyle,
  TextStyle,
  StyleSheet,
  useColorScheme,
} from "react-native"

const App = () => {
  const colorScheme = useColorScheme()
  const isLightTheme = colorScheme === "light"

  const viewStyles: ViewStyle[] = [
    styles.container,
    { backgroundColor: isLightTheme ? "white" : "black" },
  ]
  const textStyles: TextStyle[] = [
    styles.text,
    { color: isLightTheme ? "black" : "white" },
  ]

  return (
    <View style={viewStyles}>
      <Text style={textStyles}>Hello, world!</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
})

export default App
```

> NOTE: [If you have the chrome debugger enabled `useColorScheme` will always return 'light'](https://reactnative.dev/docs/usecolorscheme#supported-color-schemes).

## Improving Reusability with useColorScheme

Currently our component needs to know the color theme to determine what color to use. We can put our app colors into a `Colors` object where we define colors based on the theme.

Then, in the component, we can just say we want to use `colors.background` or `colors.text`. Something descriptive.

```tsx
import React from "react"
import {
  View,
  Text,
  ViewStyle,
  TextStyle,
  StyleSheet,
  useColorScheme,
} from "react-native"

const Colors = {
  light: {
    background: "white",
    text: "black",
  },
  dark: {
    background: "black",
    text: "white",
  },
}

const App = () => {
  const colorScheme = useColorScheme()
  const colors = Colors[colorScheme]

  const viewStyles: ViewStyle[] = [
    styles.container,
    { backgroundColor: colors.background },
  ]
  const textStyles: TextStyle[] = [styles.text, { color: colors.text }]

  return (
    <View style={viewStyles}>
      <Text style={textStyles}>Hello, world!</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
})

export default App
```

## TypeScript Tip: Dealing with useColorScheme null Type

You may be seeing a warning when trying to access `Colors[colorScheme]` because `colorScheme` may be `null`...

This is a nice tip I saw in an [Expo Template](https://github.com/expo/expo/tree/main/templates/expo-template-tabs) on how to fix this.

We can create a custom `useColorScheme` hook that changes the return type to not be null via `NonNullable`.

```tsx
// hooks/ColorSchemeName.ts

import {
  ColorSchemeName,
  useColorScheme as _useColorScheme,
} from "react-native"

// The useColorScheme value is always either light or dark, but the built-in
// type suggests that it can be null. This will not happen in practice, so this
// makes it a bit easier to work with.
export default function useColorScheme(): NonNullable<ColorSchemeName> {
  return _useColorScheme() as NonNullable<ColorSchemeName>
}
```

Creating your own `useColorScheme` hook is also nice if you want to "fake" a different color scheme/quickly change through them. Rather than returning the result of `_useColorScheme` you can just return `dark` or `light`.

## Custom useThemeColors Hook

Finally, in an effort to write even more reusable code, we can simplify our logic further and create a `useThemeColors` hook to return just the colors of the current theme without the component having to be aware of what the current theme is.

```tsx
// hooks/useThemeColors.ts
import useColorScheme from "hooks/useColorScheme"

const Colors = {
  light: {
    background: "white",
    text: "black",
  },
  dark: {
    background: "black",
    text: "white",
  },
}

const useThemeColors = () => {
  const colorScheme = useColorScheme()
  const colors = Colors[colorScheme]

  return colors
}

export default useThemeColors
```

> Further reading: [how to set up path alias', like shown above, in a React Native + TypeScript project](https://www.reactnativeschool.com/how-to-setup-path-alias-in-a-react-native-typescript-app).

Now your `App.tsx` can be as simple as

```tsx
import React from "react"
import { View, Text, ViewStyle, TextStyle, StyleSheet } from "react-native"

import useThemeColors from "hooks/useThemeColors"

const App = () => {
  const colors = useThemeColors()

  const viewStyles: ViewStyle[] = [
    styles.container,
    { backgroundColor: colors.background },
  ]
  const textStyles: TextStyle[] = [styles.text, { color: colors.text }]

  return (
    <View style={viewStyles}>
      <Text style={textStyles}>Hello, world!</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
})

export default App
```

Now within our component we don't have to do anything to figure out the current theme or which colors to use for that them. The `useThemeColors` hook encapsulates all of that and returns a color object from which we can choose the right color for our UI elements.

## Expanded Example

You can find an expanded version of this code in a more real-world example in [React Native School's Clock example app](https://github.com/ReactNativeSchool/expo-clock-app).

![Multi-theme Clock](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxiifh4x0dmjccac0k6f.png)