Log In

Styling my React Native app


by Yariv Katz

When using React Native to build our mobile application, we can no longer use CSS to style our application. We will need to style our app using CSS-in-JS way. The styling syntax will change a bit as well, we will have to use camel case (cause we are in JS) for the keys so background-color will turn into backgroundColor. Not all the styles we use in CSS will be supported but most of them will be, also animations we are no longer dealing in our styling code. But the most important thing I want you guys to gain from this article is best practices when styling a React Native project and we will use a good Styles in JS library to style our React components, that library is called: styled-components and is recommended for both React and React Native. A hell of a lot of quality information to gain from this article so stay tuned...

Bootstrapping a new React Native project

To experiment with all the things we will learn, let's build a playground app so we can try and write code and see the result. In your terminal type:

> npx react-native-cli init ReactNativeStyling

Make sure you manage to run your app on a simulator using the command:

> npx react-native run-ios

If that didn't work for you, follow these instructions again. If it did work for you let's continue to experiment with the styles.

Built in styling

Every core component of React Native contains a style property. Let's examine this property. Edit the file App.js to this:

import React from 'react';
import {
  View,
  Text,
} from 'react-native';


const App = () => {
  return (
      <View style={ {backgroundColor: 'red', height: '100%', justifyContent: 'center'} }>
        <Text style={ {textAlign: 'center', fontSize: 30} }>
          Hello world
        </Text>
      </View>
  );
};

export default App;

The easiest way to style our app is by simply place in the style property and object with our styles. The style keys will be camel cased. I would recommend to try and avoid this kind of styling cause the styles in your app will be very unreusable.

StyleSheet

Instead of placing an Object in the style property, we can also use the StyleSheet object to create our styles. With this we can easily make an object similar to a stylesheet CSS and place it in a seperate file if we are more comfortable of seperating our JS logic and our styling logic. This will also allow us to create style classes which are reusable throughout our app. Let's create the styles of our App.js in a separate file. Create another file in the root directory called: App.styles.js with the following:

import {StyleSheet} from 'react-native';

export default StyleSheet.create({
    container: {
        backgroundColor: 'blue',
        height: '100%',
        justifyContent: 'center'
    },
    text: {
        textAlign: 'center',
        fontSize: 30
    }
});

Very similar to the styles we created earlier only this time they are in seperate file, divided to classes and reusable throught our app. Now let's use that stylesheet in our App.js change to this:

import React from 'react';
import {
  View,
  Text,
} from 'react-native';
import appStylesheet from './App.styles';


const App = () => {
  return (
      <View style={ appStylesheet.container }>
        <Text style={ appStylesheet.text }>
          Hello world
        </Text>
      </View>
  );
};

export default App;

Our app will be a bit more organised if we will use the Stylesheet to create our styles.

Organising our styles

To improve user experience it's important that our app will have a constant style language. This means that a lot of our design will be shared throughout the entire app. It will be a good idea to create StyleSheet objects that describe our global style language. In the root directory of the project, create a directory called: styles this directory will contain our app Style language. Create in that file another file called: typography.js that will contain our global app typography styles. That file will contain the following code:

import { StyleSheet, Platform } from 'react-native';

export default StyleSheet.create({
    text: {
        fontFamily: Platform.OS === 'ios' ? 'Arial' : 'Roboto',
        color: 'black'
    },
    h1: {
        fontSize: 45,
        color: 'white'
    },
    h2: {
        fontSize: 30
    }
});

This file will contain in one place the entire typography styles of our app and every time we want to add text we will just choose the proper styling from this file. Notice that the text key contain common styling for all the texts in our app so we will have to include this style one every Text component. Also in the text style we are selecting different font family based on the Platform running our code so if the platform is ios the font will be Arial and if the OS is Android the font will be Roboto. Now to use our typography styles modify the file App.js to the following:

import React from 'react';
import {
  View,
  Text,
  StyleSheet
} from 'react-native';
import typographyStyles from './styles/typography';
import appStylesheet from './App.styles';


const App = () => {
  return (
      <View style={ appStylesheet.container }>
        <Text style={ StyleSheet.flatten([typographyStyles.text, typographyStyles.h1]) }>
          Hello world
        </Text>
      </View>
  );
};

export default App;

Notice that we changed the style property on our Text component and use the StyleSheet.flatten to combine multiple style classes. We placed in the styles a color key to emphasize that the flatten will start from the left and move over to the classes on the right where the right one will get more power. The only problem here is that we will have to place on each Text component those classes and flatten them. This could be a bit redundant, so to solve this we can take the following approach:

Styled Components

We can encapsulate our global styles, our app styling language, into styled components. Let's see how we can accomplish the following with our example. In the styles directory, create another directory called typography. Transfer the file typography.js we created before to the typography directory and also create the file StyledText.js in that directory with the following code:

import React from 'react';
import { Text, StyleSheet } from 'react-native';
import typographyStyles from './typography';

export default ({children, style}) => {
    return (
        <Text style={StyleSheet.flatten([typographyStyles.text, style])}>
            {children}
        </Text>
    );
}

Notice that we are creating a Text component with our common text styles, also we are going to unite the style attribute we get from the properties with the common styles. Now to create our h1 in the same directory create the file H1.js with the following:

import React from 'react';
import StyledText from './StyledText';
import typographyStyles from './typography';
import { StyleSheet } from 'react-native';

export default ({children, style}) => {
    return (
        <StyledText style={StyleSheet.flatten([typographyStyles.h1, style])}>
            {
                children
            }
        </StyledText>
    )
}

We are doing something similar to before only this time we are using the StyledText so we won't have to deal with the common text styles, and we are also passing the styles for the h1. Now to use our component, edit the file App.js with the following:

import React from 'react';
import {
  View,
  Text,
  StyleSheet
} from 'react-native';
import appStylesheet from './App.styles';
import H1 from './styles/typography/H1';

const App = () => {
  return (
      <View style={ appStylesheet.container }>
        <H1>
          Hello world
        </H1>
      </View>
  );
};

export default App;

Notice that we are not using the regular Text component anymore rather we are using our own styled component instead. With this approach throughout the designs of the different components and screens we will simply used our set of styled components, so the core react native components will be replaced with our own styled components.

styled-components library

For me, managing a large team of developers, using styled components was kind of a relief. The dev team was instructed to only use components from the styled components directory, this enforced my app to have the same style patterns throughout the entire application. If you liked this concept of using styled components, my recommendation is using a library called styled-components to help you achieve your goals. We will start by installing the library using npm.

> npm install styled-components --save

Now let's try to use styled-components to create a styled form components. In the styles directory, create another directory called: forms, and in this directory create a file called: StyledTextInput.js with the following code:

import React, {useState} from 'react';
import styled from 'styled-components/native';

const StyledTextInput = styled.TextInput`
    border: 1px solid black;
    background-color: ${({isFocused}) => isFocused ? 'yellow' : 'green'};
    color: black;
    height: 50;
`;

export default ({style}) => {
    const [isFocused, setFocused] = useState(false);

    const handleFocus = () => {
        setFocused(true);
    }

    const handleBlur = () => {
        setFocused(false);
    }

    return (
        <StyledTextInput
            isFocused={isFocused}
            style={style}
            onFocus={handleFocus}
            onBlur={handleBlur}  />
    )
}

To use styled-components we need to import it and it will provide us a function we can use to create the same components only styles attached to them. The styles syntax will be similar to CSS now and not camel cased. With styled-components it's much easier to create dynamic styles that are determined by the properties, and that is exactly what we are doing to change the background color when the input is focused. In the component itself we are creating a hook to create a variable attached to the state and we toggle it when the input is focused or blurred. Now in the App.js to use our component modify to this:

import React from 'react';
import {
  View,
  Text,
  StyleSheet
} from 'react-native';
import appStylesheet from './App.styles';
import H1 from './styles/typography/H1';
import StyledTextInput from './styles/forms/StyledTextInput';

const App = () => {
  return (
      <View style={ appStylesheet.container }>
        <H1>
          Hello world
        </H1>
        <StyledTextInput />
        <StyledTextInput />
      </View>
  );
};

export default App;

We can now place our styled components, I placed two of them so we can check the blur and focus more easily. styled-components is really the recommended approach to style your react native application.

Summary

Let's recap what we learned in this lesson. Always separate your app to global styling language of the app, and private component styles that our unique per component. The global styling language if done properly will save you ton of time and styling in your components. The global styling should be with styled component and in that case the styled-components library will be the best weapon of choice.