Skip to main content

Icon buttons

Using icons for buttons is a very common UI pattern for mobile apps. Icons make the app feel nicer as it allwes us to have less text on your sceen, making it easier on the eyes.

We'll be using Expo Icons which is built on top of react-native-vector-icons and has a convenient website for searching for available icons.

Install @expo/vector-icons

npx expo install @expo/vector-icons
Why npx expo install

When installing new packages on an Expo app, it's recommended to use npx expo install instead of the default yarn install / npm install etc. The npx expo install command will still call your preferred package manager to install the library under the hood (the preferred package manager is determined based on the lockfile in your codebase btw), the difference is that the npx expo install command ensures we install an SDK-compatible version of the library (for libraries where these versions are tracked).

Replace the delete button with an icon

Let's replace the delete button with a cross icon.

Making icons buttons easier to press

For small icon buttons, use hitSlop to ensure the pressable areas is large enough to comfortably tap.

Add a red (#ee6055) color to the theme file:

Update: theme.ts
@@ -4,4 +4,5 @@ export const theme = {
colorBlack: "#000",
colorGrey: "grey",
colorLightGrey: "#eee",
+ colorRed: "#ee6055",
};

Use it as a background for the delete button:

Update: components/ShoppingListItem.tsx
@@ -1,4 +1,5 @@
import { TouchableOpacity, View, Alert, StyleSheet, Text } from "react-native";
+import AntDesign from "@expo/vector-icons/AntDesign";
import { theme } from "../theme";

type Props = {
@@ -37,15 +38,12 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
>
{name}
</Text>
- <TouchableOpacity
- onPress={handleDelete}
- style={[
- styles.button,
- isCompleted ? styles.completedButton : undefined,
- ]}
- activeOpacity={0.8}
- >
- <Text style={styles.buttonText}>Delete</Text>
+ <TouchableOpacity hitSlop={20} onPress={handleDelete}>
+ <AntDesign
+ name="closecircle"
+ size={24}
+ color={isCompleted ? theme.colorGrey : theme.colorRed}
+ />
</TouchableOpacity>
</View>
);
@@ -54,7 +52,7 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
const styles = StyleSheet.create({
itemContainer: {
paddingVertical: 16,
- paddingHorizontal: 8,
+ paddingHorizontal: 18,
borderBottomColor: theme.colorCerulean,
borderBottomWidth: 1,
flexDirection: "row",
@@ -65,17 +63,6 @@ const styles = StyleSheet.create({
fontSize: 18,
fontWeight: "200",
},
- button: {
- backgroundColor: theme.colorBlack,
- padding: 8,
- borderRadius: 6,
- },
- buttonText: {
- color: "#fff",
- fontWeight: "bold",
- textTransform: "uppercase",
- letterSpacing: 1,
- },
completedContainer: {
backgroundColor: theme.colorLightGrey,
borderBottomColor: theme.colorLightGrey,
@@ -85,7 +72,4 @@ const styles = StyleSheet.create({
textDecorationLine: "line-through",
textDecorationColor: theme.colorGrey,
},
- completedButton: {
- backgroundColor: theme.colorGrey,
- },
});

Use a circle / check icon on the left

Now let's also add check / circle icon buttons for the other side, based on whether the shopping list item is completed or not.

Update: components/ShoppingListItem.tsx
@@ -1,5 +1,6 @@
import { TouchableOpacity, View, Alert, StyleSheet, Text } from "react-native";
import AntDesign from "@expo/vector-icons/AntDesign";
+import Entypo from "@expo/vector-icons/Entypo";
import { theme } from "../theme";

type Props = {
@@ -30,14 +31,21 @@ export function ShoppingListItem({ name, isCompleted }: Props) {
isCompleted ? styles.completedContainer : undefined,
]}
>
- <Text
- style={[
- styles.itemText,
- isCompleted ? styles.completedText : undefined,
- ]}
- >
- {name}
- </Text>
+ <View style={styles.row}>
+ <Entypo
+ name={isCompleted ? "check" : "circle"}
+ size={24}
+ color={isCompleted ? theme.colorGrey : theme.colorCerulean}
+ />
+ <Text
+ style={[
+ styles.itemText,
+ isCompleted ? styles.completedText : undefined,
+ ]}
+ >
+ {name}
+ </Text>
+ </View>
<TouchableOpacity hitSlop={20} onPress={handleDelete}>
<AntDesign
name="closecircle"
@@ -62,6 +70,8 @@ const styles = StyleSheet.create({
itemText: {
fontSize: 18,
fontWeight: "200",
+ marginLeft: 8,
+ flex: 1,
},
completedContainer: {
backgroundColor: theme.colorLightGrey,
@@ -72,4 +82,9 @@ const styles = StyleSheet.create({
textDecorationLine: "line-through",
textDecorationColor: theme.colorGrey,
},
+ row: {
+ flexDirection: "row",
+ flex: 1,
+ alignItems: "center",
+ },
});

Checkpoint

AndroidiOS
Checkpoint