Toast animado
Una notificación que entra con muelle desde el borde que elijas y se va sola a los pocos segundos.
Ajustes
Código
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { CheckCircle2 } from "lucide-react";
const positionClasses = {
"bottom-center": "bottom-4 left-1/2 -translate-x-1/2",
"bottom-right": "bottom-4 right-4",
"top-center": "top-4 left-1/2 -translate-x-1/2",
"top-right": "top-4 right-4",
} as const;
interface ToastProps {
position?: keyof typeof positionClasses;
duration?: number;
color?: string;
title?: string;
message?: string;
}
export default function Toast({
position = "bottom-center",
duration = 3,
color = "#0071e3",
title = "Guardado correctamente",
message = "Tus cambios ya están aplicados.",
}: ToastProps) {
const [items, setItems] = useState<{ id: number }[]>([]);
const fromTop = position.startsWith("top");
const fire = () => {
const id = Date.now();
setItems((p) => [...p, { id }]);
setTimeout(() => setItems((p) => p.filter((i) => i.id !== id)), duration * 1000);
};
return (
<div className="relative flex h-72 w-full items-center justify-center">
<button
type="button"
onClick={fire}
className="rounded-full px-5 py-2.5 text-sm font-semibold text-white"
style={{ backgroundColor: color }}
>
Disparar notificación
</button>
<div
className={`absolute z-10 flex w-64 max-w-[calc(100%-2rem)] flex-col gap-2 ${positionClasses[position]}`}
>
<AnimatePresence>
{items.map((i) => (
<motion.div
key={i.id}
role="status"
initial={{ opacity: 0, y: fromTop ? -24 : 24, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: fromTop ? -16 : 16, scale: 0.95 }}
transition={{ type: "spring", stiffness: 380, damping: 28 }}
className="flex w-full items-start gap-3 rounded-xl border border-black/10 bg-white p-3.5 text-[#1d1d1f] shadow-[0_4px_12px_rgba(0,0,0,0.04),0_24px_60px_rgba(0,0,0,0.1)] dark:border-white/10 dark:bg-[#1d1d1f] dark:text-[#f5f5f7]"
>
<CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0" style={{ color }} />
<div>
<p className="text-sm font-medium">{title}</p>
<p className="mt-0.5 text-xs text-[#86868b]">{message}</p>
</div>
</motion.div>
))}
</AnimatePresence>
</div>
</div>
);
}
Prompt para IA
Pégalo en ChatGPT, Claude o Cursor y adaptará el bloque a tu proyecto con estos ajustes, aunque no uses React.
Más en Toasts
Dónde usarlo
Sirve para esos momentos de «hecho» dentro de una app: una factura guardada en un programa de facturación, un producto actualizado en el panel de una tienda, una foto de perfil cambiada. Es un toast de notificación en React que entra con un muelle suave, y si lanzas varios seguidos se colocan en fila en lugar de taparse.
Elige la posición según tu diseño: abajo a la derecha en un panel de escritorio, arriba al centro en el móvil, donde el pulgar tapa la parte de abajo. Con tres segundos basta para un mensaje corto; alarga la duración solo si el texto pide una segunda lectura.