Styling The React Native Way

Published on Jun 4, 2020

8 min read

EXPO

Originally published at Level up coding on January 14, 2019.

React Native comes with many in-built components that you can use to style cross-platform applications. Styling a mobile application is essential. I cannot put enough emphasis on how important it is for a mobile app to have a pleasing design and good use of colors can be provide a better user experience. Without a polished user interface, a potential user will be repelled by the lack of design in the mobile app.

React Native uses plain JavaScript to style. In this tutorial, you are going to explore different ways to style a React Native app by getting some hands-on experience and learning tips along the way.

Introduction

🔗

React Native uses JavaScript to style, if you have some experience with the CSS of the web, you know that styling a component is nothing more than writing code by using proper styling syntax. If you do not have any idea what CSS is, stop right here as there would be no advantage for you reading this tutorial. You need to understand a bit of CSS to continue reading the tutorial below. If you understand what backgroundColor: 'blue’ means, then you are good to go.

React Native comes in with many built-in components. Each having its own specific set of styles. These specific styles may or may not be applicable to other components.

For example, Text component supports fontWeight whereas a View component does not. However, some of the styles are similar but not exactly the same. View supports shadowColor while Text supports textShadowColor. Lastly, you have to make note that there are a few platform-specific styles such as shadowPropTypesIOS.

Different Ways to Style a React Native App

🔗

There are different ways you can add styles to your React Native component. First one is inline styling. See the example below.

1// inline example
2import React from 'react';
3import { View, Text } from 'react-native';
4
5export default function App() {
6 return (
7 <View
8 style={{
9 flex: 1,
10 justifyContent: 'center',
11 alignItems: 'center',
12 backgroundColor: 'blue'
13 }}
14 >
15 <Text style={{ color: 'white', fontSize: 32 }}>Some Text</Text>
16 </View>
17 );
18}

The result of the above code of snippet is following.

ss1

In the post Getting Started with React Native in 2019, I've described about StyleSheet object. It is the second way.

Available from React Native API, by importing and using StyleSheet, you create an object and refer to each style individually. This brings the separation of styles from the render method and helps you organize the code. Also, it promotes re-using styles across components.

1// StyleSheet Example
2import React from 'react';
3import { View, Text, StyleSheet } from 'react-native';
4
5export default function App() {
6 return (
7 <View style={styles.container}>
8 <Text style={styles.bigText}>Some Text</Text>
9 </View>
10 );
11}
12
13const styles = StyleSheet.create({
14 container: {
15 flex: 1,
16 justifyContent: 'center',
17 alignItems: 'center',
18 backgroundColor: 'blue'
19 },
20 bigText: {
21 color: 'white',
22 fontSize: 32
23 }
24});

This snippet of code will have the same effect on rendering on a mobile device. The only thing changed here is being separation of styles inside the component App with StyleSheet object. It takes a JavaScript object as it does above, and returns a new Stylesheet object from it. There are no classes or ids in React Native like in web development.

To create a new style object you use StyleSheet.create() method. Another advantage this way of styling React Native components hold is that when creating a new style object every time, StyleSheet helps to create style objects with an ID which is further used to reference instead of rendering the whole component again.

Another difference comes with inline styling is that an inline style property name, if misspelled, does not work and there is no error thrown for the misspelling.

ss2

However there is a valid style property check when styles are defined using StyleSheet.create().

ss3

ss4

Encapsulation of Styles

🔗

In React Native, styles are scoped to the component rather than the whole application. You have seen one preferred way of defining styles used commonly by the React Native community.

Another way to define styles is to organize your application code in such a way that it becomes easier to keep track of them when refactoring, or when the application starts to expand. In this second way, you declare all the styles related to a component in a separate file. Then import that styles file inside the component file. Here is an example for you. Create a new file next to the App.js called AppStyles.js.

1// AppStyles.js
2import { StyleSheet } from 'react-native';
3
4export default StyleSheet.create({
5 container: {
6 flex: 1,
7 justifyContent: 'center',
8 alignItems: 'center',
9 backgroundColor: 'blue'
10 },
11 bigText: {
12 color: 'white',
13 fontSize: 32
14 }
15});

Next step is to import this file inside App.js.

1//App.js
2import React from 'react';
3import { View, Text } from 'react-native';
4
5import styles from './AppStyles';
6
7export default function App() {
8 return (
9 <View style={styles.container}>
10 <Text style={styles.bigText}>Some Text</Text>
11 </View>
12 );
13}

The demo runs and produces the same result as before. This separation of styles in a file other than the component file has its own advantages. It increases the reusability of other style objects.

Using arrays to pass styles

🔗

In inline styling, you must have observed that it is nothing but an object that starts with a style prop and an object is passed with key-value pairs. Similarly, you can use an array that can contain multiple key-value pairs as the value of the style prop.

1import React, { Component } from 'react';
2import { View, Text, StyleSheet } from 'react-native';
3
4export default function App() {
5 return (
6 <View style={styles.container}>
7 <Text style={[styles.bigText, styles.textYellow]}>Some Text</Text>
8 </View>
9 );
10}
11
12const styles = StyleSheet.create({
13 container: {
14 flex: 1,
15 justifyContent: 'center',
16 alignItems: 'center',
17 backgroundColor: 'blue'
18 },
19 bigText: {
20 color: 'white',
21 fontSize: 32
22 },
23 textYellow: {
24 color: 'yellow'
25 }
26});

The following is the result for the above snippet.

ss5

Do notice that, the last style passed in overrides the previous style when there is a duplicate color property.

Building an App: Dark/Light Themes

🔗

In this section, you are going to build a simple app called light/dark mode toggle. It contains a button with some text with a dark background of its own and a light colored background. When the user clicks the button, the background of the app changes to dark mode and the text on the button changes to light mode.

First, let us define styles for it. Open AppStyles.js the external styling file.

1import { StyleSheet } from 'react-native';
2
3const Colors = {
4 light: 'white',
5 dark: 'black'
6};
7
8const baseContainer = {
9 flex: 1,
10 justifyContent: 'center',
11 alignItems: 'center'
12};
13
14const buttonBorderContainer = {
15 justifyContent: 'center',
16 alignItems: 'center',
17 borderWidth: 3,
18 height: 50,
19 width: 150
20};
21
22const lightStyles = StyleSheet.create({
23 container: {
24 ...baseContainer,
25 backgroundColor: Colors.light
26 },
27 button: {
28 ...buttonBorderContainer,
29 backgroundColor: Colors.dark
30 }
31});
32
33const darkStyles = StyleSheet.create({
34 container: {
35 ...baseContainer,
36 backgroundColor: Colors.dark
37 },
38 button: {
39 ...buttonBorderContainer,
40 backgroundColor: Colors.light
41 }
42});
43
44export default function useTheme(darkTheme) {
45 return darkTheme ? darkStyles : lightStyles;
46}

A lot is going on here. First, the two different color variables are defined inside a single Colors object. Then, there are two different container objects, one for the background and one for the button.

Both of these container objects then re-used inside the StyleSheet objects, lightStyles and darkStyles. Similarly, to define the background color, we make re-use of the color object such that we do not have to write the value of each color twice.

Lastly, there is a function that gets exported that returns theme based upon a boolean value. Dark Theme’s value darkStyles is returned if its true otherwise light theme is returned.

The file AppStyles.js is a clear representation of structuring styles in a React Native app. This file is then imported inside the App.js that has the following content.

1import React, { useState } from 'react';
2import { View, Button } from 'react-native';
3
4import useTheme from './AppStyles';
5
6export default function App() {
7 const [darkTheme, setDarkTheme] = useState(false);
8 const styles = useTheme(darkTheme);
9
10 const toggleTheme = () => {
11 setDarkTheme(!darkTheme);
12 };
13
14 return (
15 <View style={styles.container}>
16 <View style={styles.button}>
17 <Button title={'Click Me'} onPress={toggleTheme} />
18 </View>
19 </View>
20 );
21}

By defining the state, you can declare the default value of the dark theme to be false such as it allows the light theme to be the default. toggleTheme is the method that reverses the boolean value for the dark theme accordingly. Next, inside the render() you are passing the current value of dark theme from the state. This function is then used to apply the correct theme or set of styles based on the boolean value.

You can see this in action below.

ss6

  • You can find the complete code for the example at this Expo Snack.
  • A big thank you to Catalin Miron for proof reading it 🤗

Resources & Further Reading:

  • If you are looking for some insight on how to hire a React Native dev, Toptal.com has an awesome guide here.

More Posts

Browse all posts

Aman Mittal author

I'm a software developer and a technical writer. On this blog, I write about my learnings in software development and technical writing.

Currently, working maintaining docs at 𝝠 Expo. Read more about me on the About page.


Copyright ©  2019-2024 Aman Mittal · All Rights Reserved.