Signature
toast.custom(
content: ReactNode | CustomContentRenderFn,
options?: CustomToastOptions
): string
Parameters
content
ReactNode | CustomContentRenderFn
required
ReactNode or render function that receives { id, dismiss, type, isExiting }
Optional configuration for duration, dismissible, style, etc.
Custom content render function
When passing a function as content, it receives the following props:
Function to dismiss this toast
Toast type (defaults to “info” if not specified in options)
Whether the toast is currently exiting
Custom toast options
The options object supports the following properties:
Toast type: “success” | “error” | “info” | “loading” (default: “info”)
Stable key for deduplication
Description text (not rendered in custom content, but can be used for accessibility)
Style overrides for the toast container
Whether this toast can be dismissed via swipe
Whether to show the close button (note: custom content must render its own close button)
Enable deduplication for this toast
Return value
Returns the toast ID as a string, which can be used to dismiss the toast later.
Examples
Simple custom content
import { View, Text } from 'react-native';
toast.custom(
<View style={{ flexDirection: 'row', alignItems: 'center', padding: 16 }}>
<Text style={{ fontSize: 16 }}>🎉</Text>
<Text style={{ marginLeft: 8 }}>Custom toast!</Text>
</View>
);
With render function for dismiss access
import { View, Text, Button } from 'react-native';
toast.custom(({ dismiss }) => (
<View style={{ flexDirection: 'row', alignItems: 'center', padding: 16 }}>
<Text>Custom toast!</Text>
<Button title="Close" onPress={dismiss} />
</View>
));
With options
toast.custom(
<MyCustomToast />,
{
duration: 5000,
dismissible: false,
type: 'success',
}
);
Custom action toast
import { View, Text, TouchableOpacity } from 'react-native';
toast.custom(
({ dismiss }) => (
<View style={{
flexDirection: 'row',
alignItems: 'center',
padding: 16,
backgroundColor: '#1f2937',
borderRadius: 8,
}}>
<Text style={{ flex: 1, color: 'white' }}>
Changes saved locally
</Text>
<TouchableOpacity
onPress={() => {
syncToServer();
dismiss();
}}
style={{ marginLeft: 12, paddingHorizontal: 12, paddingVertical: 6 }}
>
<Text style={{ color: '#60a5fa', fontWeight: '600' }}>Sync</Text>
</TouchableOpacity>
<TouchableOpacity onPress={dismiss} style={{ marginLeft: 8 }}>
<Text style={{ color: '#9ca3af' }}>✕</Text>
</TouchableOpacity>
</View>
),
{
duration: 8000,
}
);
Undo toast
import { View, Text, TouchableOpacity } from 'react-native';
const handleDelete = (item) => {
// Delete the item
deleteItem(item.id);
// Show undo toast
toast.custom(
({ dismiss }) => (
<View style={{
flexDirection: 'row',
alignItems: 'center',
padding: 16,
backgroundColor: '#374151',
borderRadius: 8,
}}>
<Text style={{ flex: 1, color: 'white' }}>
Item deleted
</Text>
<TouchableOpacity
onPress={() => {
restoreItem(item);
dismiss();
}}
style={{ paddingHorizontal: 12 }}
>
<Text style={{ color: '#fbbf24', fontWeight: '600' }}>Undo</Text>
</TouchableOpacity>
</View>
),
{
duration: 5000,
type: 'info',
}
);
};
Progress toast
import { View, Text } from 'react-native';
import { useState, useEffect } from 'react';
const ProgressToast = ({ dismiss }) => {
const [progress, setProgress] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setProgress(p => {
if (p >= 100) {
clearInterval(interval);
dismiss();
return 100;
}
return p + 10;
});
}, 500);
return () => clearInterval(interval);
}, []);
return (
<View style={{ padding: 16 }}>
<Text style={{ marginBottom: 8 }}>Uploading...</Text>
<View style={{
height: 4,
backgroundColor: '#e5e7eb',
borderRadius: 2,
overflow: 'hidden',
}}>
<View style={{
height: '100%',
width: `${progress}%`,
backgroundColor: '#3b82f6',
}} />
</View>
<Text style={{ marginTop: 4, fontSize: 12, color: '#6b7280' }}>
{progress}%
</Text>
</View>
);
};
toast.custom(
<ProgressToast />,
{
duration: Infinity, // Don't auto-dismiss
dismissible: false,
}
);
Using the toast ID
// Save the toast ID to dismiss it later
const toastId = toast.custom(
<MyPersistentToast />,
{
duration: Infinity,
}
);
// Later, dismiss it manually
toast.dismiss(toastId);
Responding to exit state
toast.custom(({ isExiting }) => (
<View style={{
padding: 16,
backgroundColor: '#1f2937',
borderRadius: 8,
opacity: isExiting ? 0.5 : 1, // Fade out when exiting
}}>
<Text style={{ color: 'white' }}>Custom toast</Text>
</View>
));
Notes
- Custom content fills the entire toast container and receives entry/exit animations
- When using custom content, the default icon, title, description, and close button are not rendered
- You are responsible for implementing your own close button if needed (use the
dismiss function from the render props)
- The custom content receives the same container styles as standard toasts (unless overridden with the
style option)
- Use
duration: Infinity for toasts that should persist until manually dismissed