Skip to main content

Styling

React Native uses JavaScript to style the app and all styles are bound to the component at hand. So there is no CSS and there is no global style. Your styles are JavaScript code!!!

Also, there are 3 Layout Systems available in React Native:

  • Box Object Model: height/width + space of a single element
  • Flex Box: position multiple elements within a common parent; define layout
  • Position: positioning of a single element

To style your components you can either use the standard mechanism which is Stylesheet API, or a more CSS like approach with styled components or both together. A general introduction is available here.

Layout Systems

To proper style a React Native application you will have to combine the 3 layout systems. The layout process first processes the Box Object Model, then Flex Box and in the end applies Position.

Box Object Model

The box has the following levels and style-properties, starting from inner to outer box:

  • content: height, width
  • padding: padding, paddingHorizontal, paddingVertical, paddingTop, paddingRight, paddingBottom, paddingLeft
  • border: borderWidth, borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth
  • margin: margin, marginHorizontal, marginVertical,marginTop, marginRight, marginBottom, marginLeft

Flex Box

I completely understand if you don't have time for this, just use this tool.

A few important definitions first:

  • flex container: An element on which the display value is set to flex
  • flex item: Direct child of a flex container
  • main/primary axis: The axis defined by the flexDirection property
  • cross axis: The axis perpendicular to the main axis

The official documentation on Flex Box provided by React Native is very good. To wrap it up, you would define these properties on the parent:

  • flexDirection: whether to align children vertically (column (default) )or horizontally (row)
  • alignItems: where to place children w.r.t. the cross axis (stretch - take as much space as possible (default), flex-start, center, flex-end)
  • justifyContent: lay out children along the main axis (flex-start (default), center, flex-end, space-between, space-around)

And these properties on the child:

  • flex: how much space does the child take up (flex: 1 - as much space as possible, if > 1 then proportionally)
  • alignSelf: essentially overwrites alignItems from parent (same values as alignItems)

To get more familiar with Flex Box you can play around with this.

Position

The position property can have the following 2 values:

  • relative (default): the element gets managed by the parent w.r.t. other siblings
  • absolute: the element ignores other siblings, but might position itself relative to the parent (e.g. alignItems: stretch gets ignored)

Additionally you can use top, right, bottom and left to position elements. E.g. a top: 10 would shift a child 10 units down (as 10 units get added on top of the child) and as such it might overlap a sibling if present. It is important to understand that this will happen as the last step of the layout process, so after all flex box rules have been applied. You can use this to escape the parent's layout. E.g. by using position: absolute and using 0 for each of these properties just mentioned one component might fill out the whole parent just like an overlay.

API

You can either use inline styling (not recommended), the Stylesheet API (default) or Styled Components. It is common in RN to put styles in the same file as the component at the bottom of the file (after the component). In this way your whole component is encapsulated in one file and can easily be moved. However, if you prefer to put your styles in a separate file (extension is .js!), then you can do that as well.

Inline

When choosing the inline-way then your styles are not reusable by other components and your JSX is harder to read. Therefore it is recommended to externalize the styling either by using the default Stylesheet API or Styled Components.

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

export const SomeComponent = () => {
return (
<View style={{ backgroundColor: 'white' }}>
<Text style={{ color: 'red' }}>just red</Text>
</View>
);
};

Stylesheet

React Native uses the Stylesheet API which, as React, DOES NOT recognize CSS. The API processes an object where property names are camel cased (e.g. backgroundColor instead of background-color) and non-numeric values are wrapped in quotes.

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

export const SomeComponent = () => {
return (
<View style={styles.container}>
<Text style={styles.red}>just red</Text>
</View>
);
};

const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
red: {
color: 'red',
},
});

The problem with this API is that values are unit-less, hence a fontSize of 16 would render differently on devices with different pixel densities.

const styles = Stylesheet.create({
fontSize: 16
});

Styled Components

Links:

React Native Styled Components rely on css-to-react-native to translate CSS to the Stylesheet API. However, it does not recognise em- or rem-units, and will cause a runtime error if you try to use them.

Setup

Install via: npm i styled-components @types/styled-components

Import via:import styled from 'styled-components/native'

Use together with Stylesheet API

With Styled Components we can reduce the styling boilerplate of this:

import { SafeAreaView } from 'react-native'
const App = () => (
<SafeAreaView style={{ flex: 1 }}>
...
</SafeAreaView>
);

To that:

// styles.jsx
import styled from 'styled-components'
export const StyledSafeAreaView = styled.SafeAreaView`
flex: 1,
`;

// App.jsx
import { StyledSafeAreaView } from './styles'
const App = () => (
<StyledSafeAreaView>
...
</StyledSafeAreaView>
);

However, as we're dealing with two different styling approaches, mixing them might be confusing.

import { StyleSheet } from 'react-native'
export const styles = StyleSheet.create({
shadowColor: '#000',
shadowOpacity: 0.25,
shadowOffset: {
width: 0,
height: 2
}
}

// vs

export const StyledView = styled.View`
box-shadow: 0px 2px 1px rgba(0,0,0,0.25);
`;