logo

Demystifying Flexbox in React Native

May 23, 2019

Learn how to use Flexbox with React Native

Photo by [Hamed Daram](https://unsplash.com/@hameddaram?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

React native uses Flexbox to handle the layout. Flexbox makes it easy to distribute the UI elements in the container. The way that flexbox works in React Native is a bit different than the way it works on the web — that’s why we are going to demystify it here and give you a clear idea of how FlexBox in React Native deals with the Layout.

Tip: Use Bit to easily share and reuse React components to build apps. It’s free and open source — so feel free to jump in and make your components reusable!

!Bit’s Visual Collection[](./asset-2.gif)

In React Native we have two options to define the layout, first, we can use the classic way using width and height properties, secondly React Native offer us Flexbox method which is great to distribute the elements within the container, and there is no **CSS-Grid** — only the two options I mentioned so we are going to cover most uses case of Flexbox. let’s start first with flex property.

Using Flex property

We mostly assign flex to the parent, it specifies how much space the element should take from the available space, for example, if we put flex:1 this makes the element take all the available space in the axis, as the example below explains:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, { Component } from "react"
import { StyleSheet, View, Text } from "react-native"

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Hello world</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "orange",
  },
})

asset 3

Let’s add some children and apply flex on them and see how it goes!

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, { Component } from "react"
import { StyleSheet, View, Text } from "react-native"

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.item1}>
          <Text style={styles.text}>Item 1</Text>
        </View>
        <View style={styles.item2}>
          <Text style={styles.text}>Item 2</Text>
        </View>
        <View style={styles.item3}>
          <Text style={styles.text}>Item 3</Text>
        </View>
        <View style={styles.item4}>
          <Text style={styles.text}>Item 4</Text>
        </View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
  item1: {
    flex: 1,
    backgroundColor: "#feffcb",
  },
  item2: {
    flex: 1,
    backgroundColor: "#c6394d",
  },
  item3: {
    flex: 1,
    backgroundColor: "#49beb7",
  },
  item4: {
    flex: 1,
    backgroundColor: "#240041",
  },
})

asset 4

What did we just do here? simply, we gave flex:1 for each child, each child takes a portion of the available space from the parent, when we give each child a flex 1 the space is distributed between the children equally, so each child has the same size, same width, and height!

Let’s do something different, let’s change the value of a specific element and see what’s happens! we change the values of item2 and the item4 :

item2: {
  flex: 3,
  backgroundColor: "#c6394d"
},
item4: {
  flex: 4,
  backgroundColor: "#240041"
}

asset 5

If you look at the example, the two element’s size has changed, and that’s because we changed the value of the flex , so you can use that if you want to give a specific size to an element, without having to use width and height — you can use flex instead.

How to define the direction of the children in the axis?

What we mean by the direction here is how the position of an element is set vertically or horizontally! for that purpose we use flexDirection

FlexDirection determines how the position of the children should be within the container vertically or horizontally in another way should be distributed by column or row . by default flexDirection is set to column in React Native!

Let add flexDirection property to the container and see how it change the Layout :

 container: {
    flex: 1,
    flexDirection: "row",
    backgroundColor: "#fff"
  }

asset 6

You see how the children are distributed horizontally when we set flexDirection to row and as we mentioned above flexDirection is set the the column by default.

How to control the position of the children within the container?

Well, we use **justifyContent** to do that, it helps us to set the position of the elements this works especially when the children don’t have a flex property, By defining justifiContent we are setting the height and width of the element to beauto , in order to make justifyContent to work we have to remove flex from the children.

The first case of using justifyContent: make all the children come to the center, this happens when we assign center to justifyContent :

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, { Component } from "react"
import { StyleSheet, View, Text } from "react-native"

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.item1}>
          <Text style={styles.text}>Item 1</Text>
        </View>
        <View style={styles.item2}>
          <Text style={styles.text}>Item 2</Text>
        </View>
        <View style={styles.item3}>
          <Text style={styles.text}>Item 3</Text>
        </View>
        <View style={styles.item4}>
          <Text style={styles.text}>Item 4</Text>
        </View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    justifyContent: "center",
  },
  text: {
    fontWeight: "bold",
    fontSize: 20,
  },
  item1: {
    backgroundColor: "#feffcb",
  },
  item2: {
    backgroundColor: "#c6394d",
  },
  item3: {
    backgroundColor: "#49beb7",
  },
  item4: {
    backgroundColor: "#240041",
  },
})

image

justifyContent:"flex-start"

image

justifyContent:"flex-end"

image

justifyContent:"space-around"

image

justifyContent:"space-between"

asset 11

The difference between justifyContent and alignItems :

> As the React Native official docs explain,`[justifyContent](https://facebook.github.io/react-native/docs/layout-props#justifycontent)` [aligns children in the main direction. For example, if children are flowing vertically,](https://facebook.github.io/react-native/docs/layout-props#justifycontent) `[justifyContent](https://facebook.github.io/react-native/docs/layout-props#justifycontent)` [controls how they align vertically](https://facebook.github.io/react-native/docs/layout-props#justifycontent), however`[alignItems](https://facebook.github.io/react-native/docs/layout-props#alignitems)` [aligns children in the cross direction. For example, if children are flowing vertically,](https://facebook.github.io/react-native/docs/layout-props#alignitems) `[alignItems](https://facebook.github.io/react-native/docs/layout-props#alignitems)` [controls how they align horizontally](https://facebook.github.io/react-native/docs/layout-props#alignitems)

How to align a specific child?

You may want to align a specific child and make it goes to a different direction, we can always use alignSelf for this purpose :

child:{

alignSelf:"center" // you flex-end ,flex-start or auto

},

From all the examples above, it seems pretty obvious that it is much easier to build your Layout with Flexbox in React Native. It makes thing clearer by defining simple properties that can do a lot of work. For my next demonstration, I will build a simple Instagram profile with a gallery so you can see how easy it is to do it using Flexbox :

asset 12

And here is the full source code:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, { Component } from "react"
import {
  StyleSheet,
  View,
  Text,
  Image,
  TouchableOpacity,
  ScrollView,
  Dimensions,
} from "react-native"
const screenWidth = Dimensions.get("window").width
const images = [
  "https://images.unsplash.com/photo-1513721032312-6a18a42c8763?w=152&h=152&fit=crop&crop=faces",
  "https://images.unsplash.com/photo-1511765224389-37f0e77cf0eb?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1497445462247-4330a224fdb1?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1502630859934-b3b41d18206c?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1515023115689-589c33041d3c?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1504214208698-ea1916a2195a?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1515814472071-4d632dbc5d4a?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1511407397940-d57f68e81203?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1518481612222-68bbe828ecd1?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1505058707965-09a4469a87e4?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1423012373122-fff0a5d28cc9?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1513721032312-6a18a42c8763?w=152&h=152&fit=crop&crop=faces",
  "https://images.unsplash.com/photo-1511765224389-37f0e77cf0eb?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1497445462247-4330a224fdb1?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1502630859934-b3b41d18206c?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1515023115689-589c33041d3c?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1504214208698-ea1916a2195a?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1515814472071-4d632dbc5d4a?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1511407397940-d57f68e81203?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1518481612222-68bbe828ecd1?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1505058707965-09a4469a87e4?w=500&h=500&fit=crop",
  "https://images.unsplash.com/photo-1423012373122-fff0a5d28cc9?w=500&h=500&fit=crop",
]
const imgProfileUrl =
  "https://images.unsplash.com/photo-1557626211-3046857aa1a0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80"
const localImg = require("./images/image.jpg")
export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.header}>
          <View style={styles.imgProfileContainer}>
            <Image source={localImg} style={styles.imgProfile} />
          </View>
          <View style={styles.userInfoContainer}>
            <View style={styles.userInfo}>
              <View style={styles.figure}>
                <Text style={styles.posts}>Posts</Text>
                <Text style={styles.post}>20</Text>
              </View>
              <View style={styles.figure}>
                <Text style={styles.followers}> Followers</Text>
                <Text style={styles.followers}>110304</Text>
              </View>
              <View style={styles.figure}>
                <Text style={styles.following}>following</Text>
                <Text style={styles.following}>1103</Text>
              </View>
            </View>
            <View styles={styles.actionButtons}>
              <TouchableOpacity style={styles.editProfileButton}>
                <Text>Edit Profile</Text>
              </TouchableOpacity>
            </View>
          </View>
        </View>
        <ScrollView contentContainerStyle={styles.imgGalleryContainer}>
          {images.map((item, index) => (
            <View style={styles.itemGallery}>
              <Image
                source={{ uri: item }}
                style={styles.imgGallery}
                resizeMode="stretch"
              />
            </View>
          ))}
        </ScrollView>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
  header: {
    flex: 0.3,
    paddingTop: 70,
    flexDirection: "row",
    justifyContent: "space-between",
  },
  userInfoContainer: {
    flex: 0.9,
    padding: 10,
  },
  userInfo: {
    flexDirection: "row",
    alignItems: "center",

    justifyContent: "space-between",
  },
  imgProfileContainer: {
    padding: 10,
    flexDirection: "row",
  },
  imgProfile: {
    width: 100,
    height: 100,
    borderRadius: 50,
  },
  username: {},
  followers: {
    fontSize: 12,
    fontWeight: "bold",
    alignItems: "center",
    textAlign: "center",
  },
  posts: {
    fontSize: 12,
    fontWeight: "bold",
  },
  following: {
    fontSize: 12,
    fontWeight: "bold",
  },
  actionButtons: {},
  editProfileButton: {
    margin: 10,
    backgroundColor: "#f4f4f4",
    shadowOffset: { width: 2, height: 4 },
    shadowColor: "#fff",
    padding: 4,
    alignItems: "center",
  },
  imgGalleryContainer: {
    flex: 1,
    flexDirection: "row",
    flexWrap: "wrap",
  },
  imgGallery: {
    width: 100,
    height: 100,
    borderWidth: 1,
    borderColor: "#fff",
  },
  itemGallery: {
    width: screenWidth / 4,
  },
})

Wrapping up

We’ve seen how flexbox allows us to define the layout in React Native. It’s really not that hard, there are a lost of libraries out there that can help you deal with layout, but If you know how to use Flexbox you won’t need to use any extra libraries. Sometimes, using a library just brings more problems when it comes to scaling and when you try to make your application compatible with different devices and screens.

Please feel free to comment if you have any questions or if you’d like to add anything to this post. I’m happy to talk on Twitter as well.