Theming React Native Applications with Styled Components
Tags: reactnative, javascript, mobile, tutorial
Published: 2022-03-02 12:31:50

_by author [Samaila Bala](https://blog.openreplay.com/authors/samaila-bala)_

Theming has become an essential part of mobile applications. Giving users the ability to switch between dark and light mode goes a long way in improving user experience and accessibility. In this article, we will be looking at how to implement dark mode in a mobile application using React native and Styled Components.

Styled components is CSS in JS solution for styling React and React native applications. This means you can write CSS in your JavaScript code rather than keeping styles in a separate stylesheet. Some of the advantages of this method are:

- **Eliminates classname bugs:** As developers, sometimes we might misspell a class name or run into specificity issues due to duplicate styles. Styled components solve this by generating unique class names for your styles.
- **Automatic critical styles:** Another disadvantage of traditional CSS is loading the entire stylesheet for every page opened, and component rendered even when some of the styles aren’t applied to elements in the page. Styled components only inject styles of components rendered which helps in improving performance
- **Simple dynamic styling:** You can adapt the style of a component based on the props of a component without having to create separate styles.


## Getting Started

We will be building a demo blog app with the [](https://expo.dev/)[Expo](https://expo.dev/) framework to show how we can use Styled components in a React native application. To get started, run the code below:


```
npm install -global expo-cli
```

The above command installs the `[expo-cli](https://docs.expo.dev/workflow/expo-cli/)`,  a tool used in bootstrapping react native applications with Expo.

After installation, run `expo init theming-mobile`  to create a react native application `theming-mobile`.  An interactive prompt will show up to select a template, choose blank and press the enter/return key to continue the installation


![January 16, 2022 9:23:47 pm - Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1a75tih3ddrcl4wtpq8.png)


Run the code below after the installation to install the necessary libraries we will need for our demo blog app.


```
expo install @react-native-async-storage/async-storage expo-linking
```

Once the process is complete, you’ve successfully bootstrapped an expo react-native application. To run the application, navigate to the project directory in a terminal and run the code `expo start` to start the expo development server. You will be presented with an interactive menu similar to the screenshot below


![February 28, 2022 3:18:34 pm - Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6mxhjjqd9l2k5jzaa3i.png)


The Expo dev server allows you to test your application locally while in development. You will need an emulator or the Expo Go App to run the app. The installation of an emulator isn’t covered in this article. Nevertheless, you can check [](https://docs.expo.dev/get-started/installation/#2-expo-go-app-for-ios-and)[here](https://docs.expo.dev/get-started/installation/#2-expo-go-app-for-ios-and) on how to install an emulator on your computer or the Expo Go app on your mobile device. 

Assuming you have an emulator installed, press the relevant key that applies to the emulator, and it’ll run the app on the emulator.


## Integrating Styled Components

We will be creating a Blog app to illustrate how to use styled-components. As earlier explained, Styled-components is used in styling React native applications. To get started with styled-components, run the code below at the root of your project to install the `styled-components` library


```
expo install styled-components
```

Next, create a `style.js` file in the root of your project directory and paste the code below.


```javascript
import styled from 'styled-components/native';
import Constants from 'expo-constants';

export const Container = styled.SafeAreaView`
    background-color: #fff;
    flex: 1;
    align-items: center;
    justify-content: center;
    padding: 20px;
    padding-top: ${Constants.statusBarHeight + 'px'};
`;
export const Header = styled.View`
    display: flex;
    width: 100%;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
`;
export const ThemeButton = styled.Pressable`
    padding: 10px;
    border: 1px solid #000;
`;
export const ThemeButtonText = styled.Text`
    font-size: 16px;
    color: #000;
`;
export const TitleText = styled.Text`
    font-weight: 600;
    font-size: ${(props) => props.fontSize || '18px'};
    color: #000;
`;
export const PostContainer = styled.View`
    padding: 10px 20px;
    width: 100%;
`;
export const PostText = styled.Text`
    color: #73737d;
    font-size: 16px;
    padding: 10px 0 0;
    font-weight: ${(props) => props.fontWeight || '400'};
`;
```


We are using `style.js` to house all our styled components to be reused in other components. Styled components work by wrapping a react native component with custom styles in template literals.


```javascript
export const Container = styled.SafeAreaView`
    background-color: #fff;
    flex: 1;
    align-items: center;
    justify-content: center;
    padding: 20px;
    padding-top: ${Constants.statusBarHeight + 'px'};
`;
```


In the example above, we create a styled component `Container` that wraps the react-native `SafeAreaView` component. We can also pass the components' `props` and other valid JavaScript code as the styles are wrapped in template literals as you can see in the following example:


```javascript
export const PostText = styled.Text`
    color: #73737d;
    font-size: 16px;
    padding: 10px 0 0;
    font-weight: ${(props) => props.fontWeight || '400'};
`;
```


We can complete the application now that we’ve created our styled components. Create a `data.js` file in the application directory and paste the code below


```javascript
export default [
    {
        id: 1,
        body: 'Top 3 design patterns used to create React.JS components that you should know about',
        title: '3 React Component Design Patterns You Should Know About',
        date: '11th Jan 2022',
        url: 'https://blog.openreplay.com/3-react-component-design-patterns-you-should-know-about',
    },
    {
        id: 2,
        body: 'Generate Github issues directly from the OpenReplay interface',
        title: 'Integrating OpenReplay with GitHub',
        date: '5th Nov 2021',
        url: 'https://blog.openreplay.com/integrating-openreplay-with-github',
    },
    {
        id: 3,
        body: 'Learn how to create JIRA tickets directly from an OpenReplay session',
        title: 'Integrating OpenReplay with Jira',
        date: '24th Sept 2021',
        url: 'https://blog.openreplay.com/integrating-openreplay-with-slack-in-a-web-application',
    },
];
```
    

This file will hold the mock blog data we will be using in our application. Create another file called  `PostItem.js` file in your project directory and insert the code below


```javascript
import * as Linking from 'expo-linking';
import { PostContainer, TitleText, PostText } from './style';
const PostItem = ({ item }) => {
    return (
        <PostContainer>
            <TitleText onPress={() => Linking.openURL(item.url)}>{item.title}</TitleText>
            <PostText>{item.body}...</PostText>
            <PostText fontWeight='600'>{item.date}</PostText>
        </PostContainer>
    );
};
export default PostItem;
```


The `PostItem` component will display a single blog post item that comprises the Blog title, body, and date the blog article was published. As you can notice, we aren’t using any React native component here directly but the styled-components we created.

Now open the `App.js` file and replace the code in the file with the code below


```javascript
import { useState, useEffect } from 'react';
import { StatusBar } from 'expo-status-bar';
import { FlatList } from 'react-native';
import PostItem from './PostItem';
import data from './data';
import { Container, Header, ThemeButton, ThemeButtonText, TitleText } from './style';
export default function App() {
    return (
          <Container>
              <Header>
                  <TitleText fontSize='24px'>Blog</TitleText>
                  <ThemeButton>
                      <ThemeButtonText onPress={() => null}>
                          Dark Mode
                      </ThemeButtonText>
                  </ThemeButton>
              </Header>
              <FlatList data={data} renderItem={PostItem} keyExtractor={(item) => item.id} />
              <StatusBar style='auto' />
          </Container>
    );
}
```


Like what was done in the `PostItem.js` component, we use our styled components to replace the default components. We also introduced a `FlatList` component to render the mock data from the `data.js` file in the `PostItem` component. 

Save and reload your emulator. You should get something similar to the screenshot below.


![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/llfi3l8mnfretj7h1e9f.png)


## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue.
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).

## Theming

Now that we have our application up and running, the next step is applying the themes. We already have a default light mode theme. We will implement a dark mode theme in this section. Create a `theme.js` file and paste the code below


```javascript
const darkTheme = {
    PRIMARY_COLOR: '#000',
    SECONDARY_COLOR: '#73737d',
    TITLE_COLOR: '#fff',
    BACKGROUND_COLOR: '#111216',
    BUTTON_COLOR: '#fff',
};
const lightTheme = {
    PRIMARY_COLOR: '#fff',
    SECONDARY_COLOR: '#73737d',
    TITLE_COLOR: '#000',
    BACKGROUND_COLOR: '#fff',
    BUTTON_COLOR: '#000',
};
export { lightTheme, darkTheme };
```


This file contains the theme colors we will be using in the application. Now go back to the `style.js` code and replace the code with the code below


```javascript
import styled from 'styled-components/native';
import Constants from 'expo-constants';
export const Container = styled.SafeAreaView`
    background-color: ${(props) => props.theme['PRIMARY_COLOR']};
    flex: 1;
    align-items: center;
    justify-content: center;
    padding: 20px;
    padding-top: ${Constants.statusBarHeight + 'px'};
`;
export const Header = styled.View`
    display: flex;
    width: 100%;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
`;
export const ThemeButton = styled.Pressable`
    padding: 10px;
    border: 1px solid ${(props) => props.theme['BUTTON_COLOR']};
`;
export const ThemeButtonText = styled.Text`
    font-size: 16px;
    color: ${(props) => props.theme['BUTTON_COLOR']};
`;
export const TitleText = styled.Text`
    font-weight: 600;
    font-size: ${(props) => props.fontSize || '18px'};
    color: ${(props) => props.theme['TITLE_COLOR']};
`;
export const PostContainer = styled.View`
    padding: 10px 20px;
    width: 100%;
`;
export const PostText = styled.Text`
    color: ${(props) => props.theme['SECONDARY_COLOR']};
    font-size: 16px;
    padding: 10px 0 0;
    font-weight: ${(props) => props.fontWeight || '400'};
`;
```


We’ve replaced the colours with `props` that will be passed down depending on the theme selected, so if a user selects dark mode, we’ll apply the colours from the `darkMode` theme in the `theme.js` folder to the styled-components.

Now go to the `App.js` file and paste the code below.


```javascript
/** Previous code **/
import { ThemeProvider } from 'styled-components/native';
import { darkTheme, lightTheme } from './theme';

export default function App() {
    const [theme, setTheme] = useState('light');
    const toggleTheme = async () => {
        const themeValue = theme === 'dark' ? 'light' : 'dark';
        setTheme(themeValue); 
    };
    return (
        <ThemeProvider theme={theme === 'dark' ? darkTheme : lightTheme}>
            <Container>
                <Header>
                    <TitleText fontSize='24px'>Blog</TitleText>
                    <ThemeButton>
                        <ThemeButtonText onPress={() => toggleTheme()}>
                            {theme === 'dark' ? 'Light' : 'Dark'} Mode
                        </ThemeButtonText>
                    </ThemeButton>
                </Header>
                <FlatList data={data} renderItem={PostItem} keyExtractor={(item) => item.id} />
                <StatusBar style='auto' />
            </Container>
        </ThemeProvider>
    );
}
```


Styled components have theming support by default which is available with the `ThemeProvider` component based on React context. The `ThemeProvider` component allows us to pass data through the component tree without drilling `props` down through every component level. 


```html
<ThemeProvider theme={theme === 'dark' ? darkTheme : lightTheme}>
```

We pass the `theme` value down, which returns a theme object that depends on the state, so when a user toggles the theme, we update the `theme` state with the correct theme value and pass down the colours of the chosen theme to the styled-components. Reload the app, and now when you click the Dark mode button, it should switch the theme


![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nz3ksz5ty50un4ugii4d.gif)



## Persisting the theme

We have now successfully created two themes for the application: light mode and dark mode, which is the aim of this article, but there is a small problem. If you reload the app, you’ll notice the theme resets back to light mode even after switching to dark mode. 

To fix that, we will be using a React native library called [](https://react-native-async-storage.github.io/async-storage/)[Async Storage](https://react-native-async-storage.github.io/async-storage/) which provides a persistent storage that we can use to store string data. The idea is to store the current theme so that we can fetch the stored theme when the app is loaded and apply it to the application.

Go to your App.js file and insert the code below:


```javascript
/** Previous code **/
import AsyncStorage from '@react-native-async-storage/async-storage';

export default function App() {
    const [theme, setTheme] = useState('light');
    useEffect(() => {
        getTheme();
    }, []);
    const getTheme = async () => {
        try {
            const themeValue = await AsyncStorage.getItem('@theme');
            if (themeValue) setTheme(themeValue);
        } catch (error) {
            console.log(error);
        }
    };
    const toggleTheme = async () => {
        const themeValue = theme === 'dark' ? 'light' : 'dark';
        try {
            await AsyncStorage.setItem('@theme', themeValue);
            setTheme(themeValue);
        } catch (error) {
            console.log(error);
        }
    };
    return(
      /** Previous code **/
    )
}
```


There are two functions to note in the code above the `getTheme` and `toggleTheme` functions. When the app loads for the first time, we check if there is an existing theme in the Async storage. If there is, we replace the default theme in the state with the existing one. If a user toggles the theme, we store the current theme in the Async storage and the theme state.

Now refresh your app again. You'll notice even when you quit and open the app again. It still uses the last saved theme.

## Conclusion

At this point, you should be able to implement theming in your mobile applications. You could do so much more with Styled components, such as creating a design system and extending the styled-components. Please endeavour to check the Styled component [](https://styled-components.com/docs)[docs](https://styled-components.com/docs). You can also try extending the app we created to include other themes. I’d love to see what you come up with. The complete code for this article is available [](https://github.com/sa-ma/theming-mobile)[here](https://github.com/sa-ma/theming-mobile).