Toast
Toast and alert notifications on mobile using Alert.alert() and custom toast components.
Toast
Mobile apps need feedback for user actions. ScaleRocket Mobile supports both native alerts and custom toast notifications.
Native Alert
The simplest approach is React Native's built-in Alert.alert():
import { Alert } from "react-native";
// Simple alert
Alert.alert("Success", "Your profile has been updated.");
// Alert with actions
Alert.alert(
"Delete Account",
"Are you sure? This action cannot be undone.",
[
{ text: "Cancel", style: "cancel" },
{ text: "Delete", style: "destructive", onPress: handleDelete },
]
);| Platform | Behavior |
|---|---|
| iOS | Native modal dialog |
| Android | Material dialog |
When to Use Alert vs Toast
| Scenario | Use |
|---|---|
| Destructive confirmation | Alert.alert() with actions |
| Success feedback | Toast |
| Error message | Toast (non-blocking) or Alert (critical) |
| Network error | Toast with retry action |
| Form validation | Inline errors (not toast) |
Custom Toast Component
For non-blocking notifications, use a custom toast:
import { useRef } from "react";
import { Animated, Text, StyleSheet } from "react-native";
interface ToastProps {
message: string;
type?: "success" | "error" | "info";
}
function Toast({ message, type = "info" }: ToastProps) {
const opacity = useRef(new Animated.Value(0)).current;
const show = () => {
Animated.sequence([
Animated.timing(opacity, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}),
Animated.delay(2000),
Animated.timing(opacity, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}),
]).start();
};
const colors = {
success: "#10B981",
error: "#EF4444",
info: "#3B82F6",
};
return (
<Animated.View
style={[styles.toast, { opacity, backgroundColor: colors[type] }]}
>
<Text style={styles.text}>{message}</Text>
</Animated.View>
);
}
const styles = StyleSheet.create({
toast: {
position: "absolute",
top: 60,
left: 16,
right: 16,
padding: 16,
borderRadius: 12,
zIndex: 1000,
},
text: { color: "white", fontWeight: "600", textAlign: "center" },
});Toast Context
Create a context so any screen can trigger a toast:
import { createContext, useContext, useState, useCallback } from "react";
const ToastContext = createContext<{
show: (message: string, type?: "success" | "error" | "info") => void;
} | null>(null);
export function ToastProvider({ children }: { children: React.ReactNode }) {
const [toast, setToast] = useState<ToastProps | null>(null);
const show = useCallback((message: string, type: "success" | "error" | "info" = "info") => {
setToast({ message, type });
setTimeout(() => setToast(null), 3000);
}, []);
return (
<ToastContext.Provider value={{ show }}>
{children}
{toast && <Toast message={toast.message} type={toast.type} />}
</ToastContext.Provider>
);
}
export const useToast = () => useContext(ToastContext)!;Usage from any screen:
function ProfileScreen() {
const toast = useToast();
const handleSave = async () => {
try {
await saveProfile();
toast.show("Profile saved!", "success");
} catch {
toast.show("Failed to save profile", "error");
}
};
return <Button title="Save" onPress={handleSave} />;
}Setup in Root Layout
Wrap your app with ToastProvider:
// app/_layout.tsx
import { ToastProvider } from "@/components/ui/Toast";
export default function RootLayout() {
return (
<ToastProvider>
<Slot />
</ToastProvider>
);
}Toast with Action
Add an undo or retry button:
<Animated.View style={[styles.toast, { opacity }]}>
<Text style={styles.text}>{message}</Text>
{action && (
<TouchableOpacity onPress={action.onPress}>
<Text style={styles.action}>{action.label}</Text>
</TouchableOpacity>
)}
</Animated.View>