Hello everyone, welcome to this new article where we are going to explore how to make a Sortable React Native Table.

In that process we will be making a Pet resort app, showing the list of available pets, by name, gender, age, breed, weight and age.

We will be displaying the list as a table form, similar to the web version with an elegant design and we will also add the functionality to sort the table by ascending and descending order with an icon indicator.

We will be using the React Native Flatlist to make the Table, since there is no native table concept in mobile applications.

The final result will look like this.

Sortable React Native Table Example Descending Order by Name
Sortable React Native Table Example Ascending Order by Weight
Sortable React Native Table Example Descending Order by Weight

Environment Setup

To build our Sortable React Native Table, we will need few things.

The Flatlist Component

It comes by default with the React Native Library, wether you are using Expo or React Native CLI.

Check my previous React Native Flatlist Example

React Native Icons

We need to use The React Native Icons package to add the sorting order indicator.

If you are using Expo, you should have it by default within the Expo Library. All you will need is to import it.

In React Native CLI however, you will need to install it via NPM or YARN.

yarn add react-native-vector-icons

Check my previous article on how to use React Native Ionicons if it’s the first time to come across it.

Lodash library

We will need lodash library to use with React Native Table to handle the sorting functionality. As it comes with handy data manipulation tools such as arrays and objects.

Our need is for the orderBy function, to sort our data table by ascending and descending order.

You can installing directly via NPM or YARN.

yarn add lodash

Building The React Native Table

Data Table

For this app, I have prepared a JSON file with a list of pets and its data that we can use. We need to add it to the state using the useState hook.

const [ pets, setPets ] = useState([
    {
      Name: "Charlie",
      Gender: "Male",
      Breed: "Dog",
      Weight: 12,
      Age: 3
    },
    {
      Name: "Max",
      Gender: "Male",
      Breed: "Dog",
      Weight: 23,
      Age: 7
    },
    {
      Name: "Lucy",
      Gender: "Female",
      Breed: "Cat",
      Weight: 5,
      Age: 4
    },
    {
      Name: "Oscar",
      Gender: "Male",
      Breed: "Turtle",
      Weight: 13,
      Age: 23
    },
    {
      Name: "Daisy",
      Gender: "Female",
      Breed: "Bird",
      Weight: 1.7,
      Age: 3
    },
    {
      Name: "Ruby",
      Gender: "Female",
      Breed: "Dog",
      Weight: 6,
      Age: 3
    },
    {
      Name: "Milo",
      Gender: "Male",
      Breed: "Dog",
      Weight: 11,
      Age: 7
    },
    {
      Name: "Toby",
      Gender: "Male",
      Breed: "Dog",
      Weight: 34,
      Age: 19
    },
    {
      Name: "Lola",
      Gender: "Female",
      Breed: "Cat",
      Weight: 4,
      Age: 3
    },
    {
      Name: "Jack",
      Gender: "Male",
      Breed: "Turtle",
      Weight: 13,
      Age: 23
    },
    {
      Name: "Bailey",
      Gender: "Female",
      Breed: "Bird",
      Weight: 2,
      Age: 4
    },
    {
      Name: "Bella",
      Gender: "Female",
      Breed: "Dog",
      Weight: 6,
      Age: 10
    }
  ])

We will also need to add few states to our app to handle different Table data. Such as the selectedColumn, Direction of the sort e.g Ascending and Descending and the list of Table Header Columns.

  const [ columns, setColumns ] = useState([
    "Name",
    "Gender",
    "Breed",
    "Weight",
    "Age"
  ])
  const [ direction, setDirection ] = useState(null)
  const [ selectedColumn, setSelectedColumn ] = useState(null)

Table View Using Flatlist

As I have mentioned, we are going to use the flatlist component to make our Table In React Native. We will add few props configurations and everything will be set.

ListHeaderComponent: The Flatlists header component, which will serve as our table component.

stickyHeaderIndices: Prop to make the Table Header stick and not scroll when we are scrolling through the data table rows.

<FlatList 
  data={pets}
  style={{width:"90%"}}
  keyExtractor={(item, index) => index+""}
  ListHeaderComponent={tableHeader}
  stickyHeaderIndices={[0]}
  renderItem={({item, index})=> {
    return (
      <View style={{...styles.tableRow, backgroundColor: index % 2 == 1 ? "#F0FBFC" : "white"}}>
        <Text style={{...styles.columnRowTxt, fontWeight:"bold"}}>{item.Name}</Text>
        <Text style={styles.columnRowTxt}>{item.Gender}</Text>
        <Text style={styles.columnRowTxt}>{item.Breed}</Text>
        <Text style={styles.columnRowTxt}>{item.Weight}</Text>
        <Text style={styles.columnRowTxt}>{item.Age}</Text>
      </View>
    )
  }}
/>

Adding A Table View Header

Using the column list we setup in the state, we will map through it and add Table Header Columns.

  const tableHeader = () => (
    <View style={styles.tableHeader}>
      {
        columns.map((column, index) => {
          {
            return (
              <TouchableOpacity 
                key={index}
                style={styles.columnHeader} 
                onPress={()=> sortTable(column)}>
                <Text style={styles.columnHeaderTxt}>{column + " "} 
                  { selectedColumn === column && <MaterialCommunityIcons 
                      name={direction === "desc" ? "arrow-down-drop-circle" : "arrow-up-drop-circle"} 
                    />
                  }
                </Text>
              </TouchableOpacity>
            )
          }
        })
      }
    </View>
  )

Here we have two interesting things happening, the onPress function of the component, which will call the sortTable() Function to re-sort the table according to the new order.
And Column Sorting order icon, which we took from MaterialCommunityIcons, based on the Direction of sorting.

Sorting Data Table Function

In this function we will be updating the state with the new data from the table column click, and sorting the data table using the lodash function _.orderBy().

  const sortTable = (column) => {
    const newDirection = direction === "desc" ? "asc" : "desc" 
    const sortedData = _.orderBy(pets, [column],[newDirection])
    setSelectedColumn(column)
    setDirection(newDirection)
    setPets(sortedData)
  }

Result

Sortable React Native Table Example Descending Order by Name, data table

Full Code

import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, FlatList, TouchableOpacity } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import _ from "lodash"



export default function App() {
  const [ columns, setColumns ] = useState([
    "Name",
    "Gender",
    "Breed",
    "Weight",
    "Age"
  ])
  const [ direction, setDirection ] = useState(null)
  const [ selectedColumn, setSelectedColumn ] = useState(null)
  const [ pets, setPets ] = useState([
    {
      Name: "Charlie",
      Gender: "Male",
      Breed: "Dog",
      Weight: 12,
      Age: 3
    },
    {
      Name: "Max",
      Gender: "Male",
      Breed: "Dog",
      Weight: 23,
      Age: 7
    },
    {
      Name: "Lucy",
      Gender: "Female",
      Breed: "Cat",
      Weight: 5,
      Age: 4
    },
    {
      Name: "Oscar",
      Gender: "Male",
      Breed: "Turtle",
      Weight: 13,
      Age: 23
    },
    {
      Name: "Daisy",
      Gender: "Female",
      Breed: "Bird",
      Weight: 1.7,
      Age: 3
    },
    {
      Name: "Ruby",
      Gender: "Female",
      Breed: "Dog",
      Weight: 6,
      Age: 3
    },
    {
      Name: "Milo",
      Gender: "Male",
      Breed: "Dog",
      Weight: 11,
      Age: 7
    },
    {
      Name: "Toby",
      Gender: "Male",
      Breed: "Dog",
      Weight: 34,
      Age: 19
    },
    {
      Name: "Lola",
      Gender: "Female",
      Breed: "Cat",
      Weight: 4,
      Age: 3
    },
    {
      Name: "Jack",
      Gender: "Male",
      Breed: "Turtle",
      Weight: 13,
      Age: 23
    },
    {
      Name: "Bailey",
      Gender: "Female",
      Breed: "Bird",
      Weight: 2,
      Age: 4
    },
    {
      Name: "Bella",
      Gender: "Female",
      Breed: "Dog",
      Weight: 6,
      Age: 10
    }
  ])

  const sortTable = (column) => {
    const newDirection = direction === "desc" ? "asc" : "desc" 
    const sortedData = _.orderBy(pets, [column],[newDirection])
    setSelectedColumn(column)
    setDirection(newDirection)
    setPets(sortedData)
  }
  const tableHeader = () => (
    <View style={styles.tableHeader}>
      {
        columns.map((column, index) => {
          {
            return (
              <TouchableOpacity 
                key={index}
                style={styles.columnHeader} 
                onPress={()=> sortTable(column)}>
                <Text style={styles.columnHeaderTxt}>{column + " "} 
                  { selectedColumn === column && <MaterialCommunityIcons 
                      name={direction === "desc" ? "arrow-down-drop-circle" : "arrow-up-drop-circle"} 
                    />
                  }
                </Text>
              </TouchableOpacity>
            )
          }
        })
      }
    </View>
  )

  return (
    <View style={styles.container}>
      <FlatList 
        data={pets}
        style={{width:"90%"}}
        keyExtractor={(item, index) => index+""}
        ListHeaderComponent={tableHeader}
        stickyHeaderIndices={[0]}
        renderItem={({item, index})=> {
          return (
            <View style={{...styles.tableRow, backgroundColor: index % 2 == 1 ? "#F0FBFC" : "white"}}>
              <Text style={{...styles.columnRowTxt, fontWeight:"bold"}}>{item.Name}</Text>
              <Text style={styles.columnRowTxt}>{item.Gender}</Text>
              <Text style={styles.columnRowTxt}>{item.Breed}</Text>
              <Text style={styles.columnRowTxt}>{item.Weight}</Text>
              <Text style={styles.columnRowTxt}>{item.Age}</Text>
            </View>
          )
        }}
      />
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    paddingTop:80
  },
  tableHeader: {
    flexDirection: "row",
    justifyContent: "space-evenly",
    alignItems: "center",
    backgroundColor: "#37C2D0",
    borderTopEndRadius: 10,
    borderTopStartRadius: 10,
    height: 50
  },
  tableRow: {
    flexDirection: "row",
    height: 40,
    alignItems:"center",
  },
  columnHeader: {
    width: "20%",
    justifyContent: "center",
    alignItems:"center"
  },
  columnHeaderTxt: {
    color: "white",
    fontWeight: "bold",
  },
  columnRowTxt: {
    width:"20%",
    textAlign:"center",
  }
});

I hope you enjoyed reading this article, And found it as informative as you have expected.
I will be adding it to Github and Expo.io, feel free to use it and share it with your friends at your will.
Stay safe and happy coding.