Tips for styling your React Native apps

It’s not going to be long before your react native app will become convoluted with styles spread all throughout your application. Even though the ability to define the styles inline on a component basis is convenient, if not properly managed it can become difficult to maintain and evolve. In this post I’ll go through a series of techniques for “theming” your react native application.

Split your styles from your components

Even when styles look simple enough, I prefer to keep styles separated from the component code. I usually do this by having a folder per component, and splitting into index.js and styles.js. I’ve also seen styles defined at the bottom of the components code as a fairly common technique.
The reason for trying to do this whenever possible, is to keep things simple and separated.

Code your styles

One of the benefits of styles in react native, is that it’s defined through code. There’s no reason not to take advantage of this, and add code into your styles definition. This includes defining variables and making calculations on realtime. Here’s an example of how you could leverage code in your styles.

import { StyleSheet } from “react-native”;
let iconSize = 24;
export default StyleSheet.create({
icon: {
height: iconSize,
width: iconSize,
borderRadius: iconSize / 2 //make this a circle
}
});

Useful things to keep in mind for coding your styles:

  • Device resolution: let { height, width } = Dimensions.get(“window”);
  • Orientation changes
  • Darken, lighten color (ie: https://www.npmjs.com/package/color)
  • Center, apply percentages
  • User preferencesLocale
  • Time of the day (apply darker themes during the night)

Notice that if your app supports both device orientations (landscape and portrait), you might have to re-run the styling logic!

Extract common components

While this might not seem related to styling, it actually makes all the difference. By extracting common components, no matter how simple they seem, you avoid having to define inline styles over and over again. One example of this, could be a Container component. This may seems as simple as:

<View style={ {flex:1} }>…</View>

However to properly extract this to a <Container> component could allow you to apply common padding logic later on. You might even have to apply different paddings depending on device orientation or screen resolution/pixel density.

Extract common styles

This might be the simpler one, you could extract common styling variables such us borderRadius, color, backgroundColor, etc…
Even when extracting common components, chances are that completely different components like a Header and a Button could use the same font size or background color. The most obvious way to do this is to define a styles/common.js (or similar) where the module exports the variables. This can be then imported by style modules.

import { StyleSheet } from “react-native”;
import { primaryColor } from “../styles/common.js”;
export default StyleSheet.create({
backgroundColor: primaryColor
//…
});

It’s always a good idea to define variables based on semantic meaning rather than it’s actual/current value. So prefer “primary”, “important”, “error”, to things like “light”, “dark”, “big”, etc…

You might also want to check a library for styling helpers like this one: https://github.com/vitalets/react-native-extended-stylesheet.

Leverage the Context

Context is a react functionality that allows parent components to pass data to child components. You can read all about it here: https://facebook.github.io/react/docs/context.html.
The way you might leverage this, is by exposing styling properties through the context, and then having your child components adjust to the current context. Suppose you want to have two themes for your app, a dark and light one for better readability of the app during day and night. You could extend your components with “higher order components” to add theming like this:

//themable.js
import React, { Component } from “React”;
//function that receives a component, and returns a new composed component.
export default ComposedComponent => class extends Component {
constructor() {
super();
if (!ComposedComponent.contextTypes) {
ComposedComponent.contextTypes = {};
}
ComposedComponent.contextTypes.theme = React.PropTypes.string;
}
static contextTypes = {
theme: React.PropTypes.string
}
static propTypes = {
theme: React.PropTypes.string
}
static childContextTypes = {
theme: React.PropTypes.string
}
getChildContext() {
return {theme: this.props.theme || this.context.theme};
}
render() {
let props = Object.assign({}, this.props, {theme: null});
return <ComposedComponent {…props} />;
}
};

This allows to wrap your components for two things, either accept a theme through props and pass it to it’s children through getChildContext(), or to receive the theme through this.context.

import React, { Component } from “React”;
import { Text } from “react-native”;
import themable from “./themable”;
class MyText extends Component {

render() {
let color = this.context.theme === ‘light’ ? ‘black’ : ‘white’;
return <Text style={{color: color}}>{ “Hello world!” }</Text>
}
}
export default themable(MyText); //leveraging this.context.theme

In order to set the theme somewhere, we can use a root component somewhere in the app like this:

import React, { Component } from “React”;
import { View } from “react-native”;
import themable from “./themable”;
import styles from “./styles.js”;
class Container extends Component {
render() {
return <View style={styles.container}>{this.props.children}</View>;
}
}
export default themable(Container); //receive theme through props

Now on the app, we can do:

 <Container theme={“dark”}>
<MyText />
</Container>

This is also a fairly common technique found in UI kits or libraries where you can define how they look in a single place of your app.

Conclusion

Working with styles in React Native apps is simple and powerful but it has it’s pitfalls. Having these things into account at the time of starting a new application can save a LOT of time and even make your application more consistent and visually appealing.