I am having issues connecting Email js with my React Hook Form, there are various issues like it wont submit on click and can't figure out a way to use ref
attribute with the <form>
tag, as it's mentioned in the official documentation.
Here's my code
'use client'
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import Image from "next/image";
import { useState } from "react";
import emailjs from '@emailjs/browser';
import contact from "@/assets/images/contact.png";
const UserValidation = z.object({
name: z.string().min(3).max(50),
email: z.string().email(),
message: z.string().min(10).max(500),
});
interface Props {
user: {
name: string;
email: string;
message: string;
};
}
const Contact = () => {
const form = useForm({
resolver: zodResolver(UserValidation),
});
const onSubmit = () => (data: z.infer<typeof UserValidation>) => {
emailjs.sendForm('__service_key', '__template__', JSON.stringify(data), '__API__')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
form.reset();
}
return (
<div className="my-20">
<div className="my-12">
<h1 className="text-3xl md:text-5xl text-center font-serif font-bold">
Contact <span className="text-primary">Us</span>
</h1>
<h1 className="text-base text-center font-sans font-thin mt-4">
We would love to hear from you
</h1>
</div>
<div className="md:grid md:grid-cols-2 mb-12">
<div className="m-12 md:m-0 md:ml-36 ">
<Form {...form} >
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField control={form.control} name="name" render={({ field }) => (
<FormItem className='flex flex-col gap-1 w-full mt-4'>
<FormLabel className='text-light-1 font-sans font-sm'>
Name
</FormLabel >
<FormControl className='flex-1 text-base-semibold text-secondary'>
<Input type='text' className='border-primary account-form_input no focus' {...field} />
</FormControl>
</FormItem>)}
/>
<FormField control={form.control} name="email" render={({ field }) => (
<FormItem className='flex flex-col gap-1 w-full mt-4'>
<FormLabel className='text-light-1 font-sans font-sm'>
Email
</FormLabel >
<FormControl className='flex-1 text-base-semibold text-secondary'>
<Input type='email' className='border-primary account-form_input no focus' {...field} />
</FormControl>
</FormItem>)}
/>
<FormField
control={form.control}
name="message"
render={({ field }) => (
<FormItem className='flex flex-col gap-1 mt-4 w-full'>
<FormLabel className='text-light-1 font-sans font-sm'>
Message
</FormLabel>
<FormControl className='flex-1 text-base-semibold text-secondary'>
<Textarea rows={10} className='border-primary account-form_input no focus' {...field} />
</FormControl>
</FormItem>
)}
/>
<div className="flex">
<Button type="submit" className='bg-primary mt-4 flex-1'>Submit</Button>
</div>
</form>
</Form>
</div>
<div className="m-12 md:m-0 md:ml-28">
<Image src={contact} alt="contact" className="rounded-lg shadow-custom" height={470} width={470} />
</div>
</div>
</div>
)
}
export default Contact;
The official documentation mentions it like:
import React, { useRef } from 'react';
import emailjs from '@emailjs/browser';
export const ContactUs = () => {
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
emailjs.sendForm('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', form.current, 'YOUR_PUBLIC_KEY')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
};
return (
<form ref={form} onSubmit={sendEmail}>
<label>Name</label>
<input type="text" name="user_name" />
<label>Email</label>
<input type="email" name="user_email" />
<label>Message</label>
<textarea name="message" />
<input type="submit" value="Send" />
</form>
);
};
you can also visit my github for the whole code: https://github.com/dipesh2508/health-optima
First, Your code has some errors
// ❌ Here you return a function that returns another function
const onSubmit = () => (data: z.infer<typeof UserValidation>) => {
// ✅ It should be
const onSubmit = (data: z.infer<typeof UserValidation>) => {
It looks like emailJs take over getting data from the input fields. It accepts the dom object.
But form.handleSubmit()
passes the values of the form, not the form object. You'll have to skip the react-hook-form submission and submit it manually.
handleSubmit
from your form:<form onSubmit={onSubmit}>
const onSubmit = (event: FormEvent<HTMLFormElement>) => {
const onSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
// Validate the form
const isValid = await form.trigger();
if (!isValid) {
// there is some validation errors
return
}
emailjs.sendForm('__service_key', '__template__', event.target, '__API__')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
form.reset();
}
Another way for doing the same is creating a ref for the form
const formRef = useRef<HTMLFormElement>(null)
// ...
const onSubmit => (data: z.infer<typeof UserValidation>) => {
emailjs.sendForm('__service_key', '__template__', formRef.current, '__API__')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
form.reset();
}
// ...
<form onSubmit={form.handleSubmit(onSubmit)} ref={formRef}>