Custom button
Let's use the versatility of the Pressable component to make a fancier button than the built-in TouchableOpacity
. We'll have it change color and emit some haptic feedback (a little vibration) when pressed.
Create a custom button component
Add a new PlantlyButton
component:
New file: components/PlantlyButton.tsx
import { theme } from "@/theme";
import { StyleSheet, Text, Pressable } from "react-native";
type Props = {
title: string;
onPress: () => void;
};
export function PlantlyButton({ title, onPress }: Props) {
return (
<Pressable onPress={onPress} style={styles.button}>
<Text style={styles.text}>{title}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
text: {
color: "white",
fontSize: 18,
fontWeight: "bold",
},
button: {
paddingHorizontal: 18,
paddingVertical: 12,
borderRadius: 6,
backgroundColor: theme.colorGreen,
},
});
and use it in the onboarding screen:
Update: app/onboarding.tsx
@@ -1,7 +1,8 @@
-import { View, StyleSheet, Button } from "react-native";
+import { View, StyleSheet } from "react-native";
import { theme } from "@/theme";
import { useUserStore } from "@/store/userStore";
import { useRouter } from "expo-router";
+import { PlantlyButton } from "@/components/PlantlyButton";
export default function OnboardingScreen() {
const toggleHasOnboarded = useUserStore((store) => store.toggleHasOnboarded);
@@ -14,7 +15,7 @@ export default function OnboardingScreen() {
return (
<View style={styles.container}>
- <Button title="Let me in!" onPress={handlePress} />
+ <PlantlyButton title="Let me in!" onPress={handlePress} />
</View>
);
}
and the profile screen:
Update: app/(tabs)/profile.tsx
@@ -1,12 +1,13 @@
-import { View, StyleSheet, Button } from "react-native";
+import { View, StyleSheet } from "react-native";
import { theme } from "@/theme";
import { useUserStore } from "@/store/userStore";
+import { PlantlyButton } from "@/components/PlantlyButton";
export default function ProfileScreen() {
const toggleHasOnboarded = useUserStore((store) => store.toggleHasOnboarded);
return (
<View style={styles.container}>
- <Button title="Back to onboarding" onPress={toggleHasOnboarded} />
+ <PlantlyButton title="Back to onboarding" onPress={toggleHasOnboarded} />
</View>
);
}
Add haptic feedback
To have our button emit some haptic feedback - a little vibration - when pressed, let's install Expo Haptics:
npx expo install expo-haptics
And trigger a light haptic feedback when the button is pressed:
Update: components/PlantlyButton.tsx
@@ -1,5 +1,6 @@
import { theme } from "@/theme";
-import { StyleSheet, Text, Pressable } from "react-native";
+import { StyleSheet, Text, Pressable, Platform } from "react-native";
+import * as Haptics from "expo-haptics";
type Props = {
title: string;
@@ -7,8 +8,15 @@ type Props = {
};
export function PlantlyButton({ title, onPress }: Props) {
+ const handlePressed = () => {
+ if (Platform.OS !== "web") {
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
+ }
+ onPress();
+ };
+
return (
- <Pressable onPress={onPress} style={styles.button}>
+ <Pressable onPress={handlePressed} style={styles.button}>
<Text style={styles.text}>{title}</Text>
</Pressable>
);
Haptics aren't supported on the web, so we'll need to add a (Platform.OS !== "web")
check to make sure we only trigger it on the mobile platforms.
Darken when pressed
The style
prop for the Pressable
component also accepts a function that exposes a boolean of whether the element is currently being pressed or not. We can use that to apply different styles to the component while it's being pressed.
Let's add a darker green to our theme file:
Update: theme.ts
@@ -1,4 +1,5 @@
export const theme = {
colorGreen: "#29b365",
+ colorLeafyGreen: "#206a42",
colorWhite: "#fff",
};
And make the button background color the darker green while pressed.
Update: components/PlantlyButton.tsx
@@ -17,7 +17,13 @@ export function PlantlyButton({ title, onPress }: Props) {
return (
<Pressable
onPress={handlePressed}
- style={styles.button}>
+ style={(state) => {
+ if (state.pressed) {
+ return [styles.button, styles.buttonPressed];
+ }
+ return styles.button;
+ }}
+ >
<Text style={styles.text}>{title}</Text>
</Pressable>
);
@@ -35,4 +41,7 @@ const styles = StyleSheet.create({
borderRadius: 6,
backgroundColor: theme.colorGreen,
},
+ buttonPressed: {
+ backgroundColor: theme.colorLeafyGreen,
+ },
});
Checkpoint
Android | iOS |
---|---|