I am developing a simple form to send messages to my email with the help of EmailJS
. The EmailJS
settings look fine, I tested them through the website and I got a 200
response.
This is my code:
"use client";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Textarea } from "./ui/textarea";
import { User, MailIcon, ArrowRightIcon, MessageSquare } from "lucide-react";
import emailjs from "@emailjs/browser";
import { ChangeEvent, FormEvent, useRef, useState } from "react";
const Form = () => {
const formRef = useRef<HTMLFormElement>(null);
const [form, setForm] = useState({
name: "",
email: "",
message: "",
});
const handleChange = (
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setForm({ ...form, [name]: value });
};
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Dati del form:", form); // Verifica i dati del form nel log
emailjs
.send(
"service_+++++",
"template_++++++",
{
from_name: form.name,
to_name: "Jhon Doe",
from_email: form.email,
to_email: "[email protected]",
message: form.message,
},
"WYI3ob++++++++"
)
.then(
() => {
alert("Thank you for your message!");
setForm({
name: "",
email: "",
message: "",
});
},
(error: Error) => {
console.log(error);
alert("Something went wrong");
}
);
};
return (
<form
ref={formRef}
onSubmit={handleSubmit}
className="flex flex-col gap-y-4"
>
<div className="relative flex items-center">
<Input
onChange={handleChange}
type="text"
id="name"
placeholder="Name"
required
value={form.name}
/>
<User className="absolute right-6" size={20} />
</div>
<div className="relative flex items-center">
<Input
onChange={handleChange}
type="email"
id="email"
placeholder="Email"
required
value={form.email}
/>
<MailIcon className="absolute right-6" size={20} />
</div>
<div className="relative flex items-center">
<Textarea
onChange={handleChange}
required
placeholder="Type your message"
value={form.message}
/>
<MessageSquare className="absolute top-4 right-6" size={20} />
</div>
<Button className="flex items-center gap-x-1 max-w-[166px] rounded-[80px]">
Let' s Talk
<ArrowRightIcon size={20} />
</Button>
</form>
);
};
export default Form;
Right now I am not able to type anything in the input
or even copy, it is like they are stuck to the initial state of empty strings.
I am also using shadcn
, in fact, the Input
and TextArea
components come from there. Anyone knows why I am facing this problem?
I also tried to use normal input
and text area
but I still can’t type into any of the inputs.
I also tried to use defaultValues
and in that case I can type into the inputs but the object with name
, email
, and message
remain an empty string.
2
Answers
Maybe you should implement the "Form" example of the shadcn documentation here.
They’re using a
I think you copy pasted the "Default" example of the documentation. But in the documentation, they’re not using a value from a useState().
Indeed, an HTML input has its own value (event.target.value). If you don’t set a value to the input, the displayed value will be
event.target.value
.In your case, you set the
form.name
as the value (here is the difference with the default documentation).This is why I think you need to implement the "Form" example because this one is using a
name
. This name is the one you retrieve inside yourevent.target.name
inside youhandleChange()
method.The issue you’re experiencing is likely due to the way you’re handling the
id
attribute in your<Input />
and<Textarea />
components and not correctly associating thename
attribute with your form’s state.For the
useState
hook to correctly update the state based on input changes, you need to ensure that thename
attribute of each input matches the keys in your state object.In your code, you’re setting the
id
attribute for<Input />
and<Textarea />
, but you’re not setting theirname
attribute, which is essential for thehandleChange
function to update the state correctly based on which input is changed.The
handleChange
function uses thename
attribute to determine which part of the state to update.Below is the updated
return ()
function based off of your shared code: