React Native Multi Select on Long Press - Touchable Opacity.

React Native Multi Select on Long Press - Touchable Opacity.

Post by: Niraj Dhungana

Posted on: Nov 13, 2021

#React Native

Do you want to know how we can select or deselect multiple Items inside react-native. Then let’s see how we can do that using TouchableOpacity and onLongPress.

react native multi select

For this project I am using bare react-native cli but it also works with expo cli as well.

You may also like: Expo vs React Native CLI

Content we will be covering in this post.

  1. Over view of the project
  2. Initializing Project
  3. Giving shape to our project
  4. Creating a ListItem component
  5. Adding all the logics
  6. Deselect on second tap

Over View of the project

Before we write any code for our react native multi select project, let’s understand what we want and how we can achieve our goal.

The feature that we want to add inside our project is that.

  • If the user just taps on the list item we want to open or navigate to a different component.
  • If the user taps and holds the finger then we want to select that list item and enable the multiple selection option.
  • Also if the user taps outside or in an empty space we want to deselect all.

Initialize a Project

You can initialize your project using npx react-native init MultipleSelect command if you are using react-native-cli like me or you can use expo init or you can use the existing react native project where you want to add this multiple select option.

After initializing your project you can run it inside an emulator or inside a physical device and please don’t ask me how to do that because you are already a pro.

Giving Shape

To create this multiple selection option I will be using some fake data with fake names and contact numbers. If you also want to use that you can copy from the example below (last of the page).

1
2
3
4
5
6
7
8
9
10
11
12
13
...
const App = () => {
  return (
    <Pressable>
      <FlatList
        data={data}
        renderItem={({item}) =><Text>{item.name}</Text>}
        keyExtractor={item => item.id}
      />
    </Pressable>
  );
};
...

Don’t worry bros and sis let me explain what is going on here. Here I am using the FlastList component to render our fake data and I hope you already know how it works. Like data, renderItem and all.

After that the new thing is that I am wrapping the FlatList component inside this new Pressable component. That is because we want to deselect all the selections if we tap outside of the list. It’s like Touchable components but it's a new thing inside react-native family.

Creating a ListItem component

Let’s create a beautiful component to render these list items and add some styles.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
const ListItem = ({item, selected, onPress, onLongPress}) => (
  <>
    <TouchableOpacity
      onPress={onPress}
      onLongPress={onLongPress}
      style={styles.listItem}>
      <View style={{padding: 8}}>
        <Text style={{fontSize: 22, color: '#fff'}}>{item.name}</Text>
        <Text style={{color: '#989BA1'}}>{item.contact}</Text>
      </View>
      {selected && <View style={styles.overlay} />}
    </TouchableOpacity>
  </>
);

const App = () => {
  const handleOnPress = () => console.log('pressed');
  const handleLongPress = () => console.log('activete long press');

  return (
    <Pressable style={{flex: 1, padding: 15}}>
      <FlatList
        data={data}
        renderItem={({item}) => (
          <ListItem
            onPress={handleOnPress}
            onLongPress={handleLongPress}
            item={item}
          />
        )}
        keyExtractor={item => item.id}
      />
    </Pressable>
  );
};
...

Here we have this beautiful ListItem component to render our list items and we are using TouchableOpacity so that we can do our secret tasks. Just joking, it is here to listen to user touch events.

As you can see clearly inside this ListItem component we are accepting an item, selected, onPress and onLongPress prop.

Item will be the actual item with data like name and contact which we will render inside here. Selected will be the condition which we are using to display an overlay on top of our list items.

This overlay is just a View component with position absolute, height and width 100% and color with half opacity. The rest of the other code is I think self explanatory.

Now our project looks like this.

react native multi select design

Now we will add a state called selectedItems inside our project so that we can add the multi select options. Feel free to use any name you like.

After that we will attach onPress and onLongPress prop and because we want to know which list item is currently pressed so we will use the inline function and pass the current item like here in example.

1
2
3
4
5
6
7
8
9
10
11
12
...
 <FlatList
   data={data}
   renderItem={({item}) => (
     <ListItem
     onPress={() => handleOnPress(item)}
     onLongPress={() => handleLongPress(item)}
     selected={getSelected(item)}     
     item={item}
     />
        )}
...

Also you may have noticed that selected={getSelected(item)}. This is to find a render that overlay if the list items are selected.

Adding all the logics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
const App = () => {
  const [selectedItems, setSelectedItems] = useState([]);

  const handleLongPress = contact => {
    selectItems(contact)
  };

  const handleOnPress = contact => {
    if (selectedItems.length) {
      return selectItems(contact)
    }

    // here you can add you code what do you want if user just do single tap
    console.log('pressed');
  };
 
  const getSelected = contact => selectedItems.includes(contact.id);

  const deSelectItems = () => setSelectedItems([]);

  const selectItems = (item) => {
    setSelectedItems([...selectedItems, item.id]);
  }
...

Here comes the actual magic guys inside this example we have everything to select multiple items inside our react native app.

First we have this selectedItems state and the default value is obviously an empty array because we don’t want to select anything at the beginning.

If you come to the end of this code block there we have a method called selectItems. Inside this method we are just accepting an item and storing that item’s id inside the selectedItems array.

Then we have handleLongPress and handleOnPress methods as well.

Inside handleLongPress we are just calling the selectItems method. So that is why we can remove this handleLongPress and directly use the selectItems method inside onLongPress prop. Which you will find inside the final code.

Inside handleOnPress we are checking if there are already some selected items then we are selecting more but if not then you can see that console log and the comment. You can do whatever you want.

Then we have another method getSelected inside this method we are just checking if the current item is already inside selectedItems or not. If yes then it will return true otherwise returns false.

Then we have the deSelectItems and inside this method we are just resetting the value of selectedItems state to an empty array. And we will attach this method to the Pressable components onPress prop.

Deselect on second tap

With these lines of code now it will select multiple items but if you try to deselect the selected one then it will do nothing. So for that we need to update our selectItems method. Like below.

1
2
3
4
5
6
7
  const selectItems = item => {
    if (selectedItems.includes(item.id)) {
      const newListItems = selectedItems.filter(listItem => listItem !== item.id);
      return setSelectedItems([...newListItems]);
    }
    setSelectedItems([...selectedItems, item.id]);
  };

Now here we have this updated selectItems method. Where we are first checking if the currently tapped item is already inside the selectedItems array or not.

If yes then we are removing it from the selectedItems list by using array filter method and returning the code execution. If not then we are adding that list item inside our selectedItems state.

Now we made our final project. Multi select using react-native. Now you can use this selectedItems state to render any other components if you want.

Like if you want to open any options, delete icons or anything that you want you can use if there is selectedItems.length then do this or that.

Ok this is it for this post. Here is the complete code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React, {useState} from 'react';
import {
  StyleSheet,
  FlatList,
  Pressable,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

const data = [
  {name: 'Rohan', contact: '1111111111', id: '1'},
  {name: 'Mohan', contact: '2222222222', id: '2'},
  {name: 'Sohan', contact: '3333333333', id: '3'},
  {name: 'Hohan', contact: '4444444444', id: '4'},
  {name: 'Dohan', contact: '5555555555', id: '5'},
  {name: 'Pohan', contact: '6666666666', id: '6'},
];

const ListItem = ({item, selected, onPress, onLongPress}) => (
  <>
    <TouchableOpacity
      onPress={onPress}
      onLongPress={onLongPress}
      style={styles.listItem}>
      <View style={{padding: 8}}>
        <Text style={{fontSize: 22, color: '#fff'}}>{item.name}</Text>
        <Text style={{color: '#989BA1'}}>{item.contact}</Text>
      </View>
      {selected && <View style={styles.overlay} />}
    </TouchableOpacity>
  </>
);

const App = () => {
  const [selectedItems, setSelectedItems] = useState([]);
  const handleOnPress = contact => {
    if (selectedItems.length) {
      return selectItems(contact);
    }

    // here you can add you code what do you want if user just do single tap
    console.log('pressed');
  };

  const getSelected = contact => selectedItems.includes(contact.id);

  const deSelectItems = () => setSelectedItems([]);

  const selectItems = item => {
    if (selectedItems.includes(item.id)) {
      const newListItems = selectedItems.filter(
        listItem => listItem !== item.id,
      );
      return setSelectedItems([...newListItems]);
    }
    setSelectedItems([...selectedItems, item.id]);
  };

  return (
    <Pressable onPress={deSelectItems} style={{flex: 1, padding: 15}}>
      <FlatList
        data={data}
        renderItem={({item}) => (
          <ListItem
            onPress={() => handleOnPress(item)}
            onLongPress={() => selectItems(item)}
            selected={getSelected(item)}
            item={item}
          />
        )}
        keyExtractor={item => item.id}
      />
    </Pressable>
  );
};

const styles = StyleSheet.create({
  container: {},
  listItem: {
    backgroundColor: '#252628',
    marginBottom: 10,
    borderRadius: 5,
    overflow: 'hidden',
  },
  overlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    width: '100%',
    height: '100%',
    backgroundColor: 'rgba(255,0,0,0.5)',
  },
});

export default App;