Search code examples
reactjstypescriptnext.jstoastshadcnui

Toast notification not triggering in Next.js contact form despite successful route and form submission


I'm working on a contact form in Next.js with server-side email functionality. The form submission is working correctly, and the email is sent successfully (verified via the network and console logs). However, the toast notification (using useToast) doesn't appear on either success or error. I've confirmed that the route and SendEmail function work as expected, and I've correctly imported and initialized the useToast hook.

Despite this, the toast doesn't show after form submission. Here's the relevant code snippet for the toast in the handleSubmit function. I'm not sure what's preventing the toast from triggering. Could there be something wrong with how I'm handling the toast state or the rendering process in the Next.js app?

"use client";

import { Input } from "@/components/ui/input";
import { Card, CardContent, CardFooter } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { SendEmail } from "@/components/send-email";
import { useToast } from "@/hooks/use-toast"; 
import { useRouter } from "next/navigation";
import { Send } from "lucide-react";

export default function ContactForm() {
    const { toast } = useToast(); 
    const router = useRouter();

    const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault(); 
        const formData = new FormData(e.currentTarget); 

        try {
            const result = await SendEmail(formData);
            if (result.success) {
                toast({
                    title: "Message Sent",
                    description: "Your message has been sent successfully.",
                });
                router.push("/");
            }
        } catch (error) {
            toast({
                title: "Error",
                description: "Failed to send the message. Please try again.",
                variant: "destructive", 
            });
        }
    };

    return (
        <Card className="w-full max-w-2xl mx-auto shadow-lg">
            <form onSubmit={handleSubmit}>
                <CardContent className="space-y-2">
                    <div className="grid grid-cols-2 gap-1">
                        <div className="flex flex-col items-start space-y-1">
                            <Input
                                type="text"
                                id="name"
                                name="name"
                                required
                                placeholder="First and Last Name"
                                className="w-full"
                            />
                        </div>
                        <div className="flex flex-col items-start space-y-1">
                            <Input
                                type="email"
                                id="email"
                                name="SenderEmail"
                                required
                                placeholder="Personal email"
                                className="w-full"
                            />
                        </div>
                    </div>
                    <div className="flex flex-col items-start space-y-0">
                        <select
                            id="subject"
                            name="subject"
                            required
                            className="w-full h-10 px-3 py-2 text-sm rounded-md border border-input bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
                        >
                            <option value="">Select a subject</option>
                            <option value="General">General Inquiry</option>
                            <option value="schedule">Schedule A Meeting</option>
                            <option value="others">Others</option>
                        </select>
                    </div>
                    <div className="flex flex-col items-start space-y-1">
                        <Textarea
                            id="message"
                            placeholder="Leave me a short message, feel free to drop your phone number if you prefer!"
                            name="message"
                            required
                            className="w-full min-h-[150px]"
                        />
                    </div>
                </CardContent>
                <div className="flex justify-center items-center">
                    <CardFooter>
                        <Button type="submit" variant={"outline"} className="w-full">
                            <Send className="w-5 h-5 mr-2" />
                            Send Message
                        </Button>
                    </CardFooter>
                </div>
            </form>
        </Card>
    );
}

I expected the toast notification to appear when the form was submitted successfully or if an error occurred. I verified that the form submission works, and the SendEmail function runs without issues. I also confirmed that the useToast hook is correctly imported and initialized. Despite this, the toast notification never appears. I tried logging the success and error states, and the logic runs as expected, but the toast itself doesn't show up on the page.

I expected a toast notification to appear either with a success message after the form submission or an error message if it failed, but nothing happens visually.


Solution

  • I can think of two reasons here.

    1. May be you haven't added the Toaster component at the root layout of the next js project.

    To confirm this, You can add a test button component to one of your page

    "use client"
    
    import { useToast } from "@/components/ui/use-toast"
    import { Button } from "@/components/ui/button"
    
    export function ToastTestButton() {
      const { toast } = useToast()
    
      return (
        <Button
          variant="outline"
          onClick={() => {
            toast({
              description: "This is a test toast message.",
            })
          }}
        >
          Show Test Toast
        </Button>
      )
    }
    

    Add this to one of your page, then check whether it works. If it is, then only cause we can think of may be

    1. Your routing happens before toast notification get showed.

    Using setTimeout try to give some delay to the router.push("/") so that toast notification can get some time to show up.

    
    if (result.success) {
     toast({
      title: "Message Sent",
      description: "Your message has been sent successfully.",
     })
    
     setTimeout(() => {
      router.push("/")
     }, 5000) // I added 5 seconds delay
    }
    
    

    Either of this should work for sure, if your implementation of toast using shadcn ui is correct.