I have the following code block from my contact form build with Next js 13 with typescript.
"use client"
import { Button, Input, TextArea } from "@/components/atom"
import { z, ZodType } from "zod"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { useEffect, useState, useRef, RefObject } from "react"
import ReCAPTCHA from "react-google-recaptcha"
type FormData = {
name: string
email: string
subject: string
form_message: string
captchaToken: string
}
const schema: ZodType<FormData> = z.object({
name: z.string().min(5, { message: "Name is required" }),
email: z.string().min(1, { message: "Email is required" }).email({
message: "Must be a valid email",
}),
subject: z.string().min(5, { message: "Subject is required" }),
form_message: z
.string()
.min(6, { message: "Message must be atleast 6 characters" }),
captchaToken: z.string(),
})
const ContactForm = () => {
const recaptcha: RefObject<ReCAPTCHA> = useRef(null)
const [showToast, setShowToast] = useState(false)
const [loading, setLoading] = useState(false)
const [err, setErr] = useState(false)
const {
register,
handleSubmit,
reset,
setValue,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(schema),
})
const submitData = async (data: FormData) => {
try {
setLoading(true)
setErr(false)
const response = await fetch("/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
})
const res = await response.json()
if (res.status === 200) {
setShowToast(true)
}
recaptcha.current?.reset()
setLoading(false)
reset()
} catch (e) {
if (e) {
setErr(true)
}
setLoading(false)
setShowToast(true)
}
}
useEffect(() => {
if (showToast) {
const timer = setTimeout(() => {
setShowToast(false)
setErr(false)
}, 3000)
return () => {
clearTimeout(timer)
}
}
}, [showToast])
const handleChange = (token: string | null) => {
if (token) {
setValue("captchaToken", token)
}
}
return (
<form onSubmit={handleSubmit(submitData)}>
<div className="formRow flex gap-6">
<Input
label="Name"
width="w-1/2"
error={errors.name ? errors.name.message : null}
placeholder="Full name"
id="name"
{...register("name")}
/>
<Input
label="Email"
type="email"
width="w-1/2"
placeholder="Email address"
id="email"
error={errors.email ? errors.email.message : null}
{...register("email")}
/>
</div>
<div className="formRow w-full gap-6">
<Input
label="Subject"
placeholder="Subject"
id="subject"
error={errors.subject ? errors.subject.message : null}
{...register("subject")}
/>
</div>
<div className="formRow w-full gap-6">
<TextArea
label="Message"
placeholder="Message"
id="form_message"
rows={5}
error={errors.form_message ? errors.form_message.message : null}
{...register("form_message")}
/>
</div>
<div className="formRow flex gap-6">
<ReCAPTCHA
size="normal"
sitekey="6Ldh6jgoAAAAAM44ieDQ6Nw1cvAWa5i2NhGjpV4a"
onChange={handleChange}
ref={recaptcha}
/>
</div>
<Button variant="primary" additionalClass="mt-5" submit loading={loading}>
Send Message
</Button>
{showToast && (
<div className="toast">
<div className={`alert ${err ? "alert-danger" : "alert-success"}`}>
<span>
{err ? "Message sending failed" : "Message sent successfully!"}
</span>
</div>
</div>
)}
</form>
)
}
export default ContactForm
I’m using react-google-recaptcha package to add google recaptcha in the above contact form.
I’ve also installed type @types/react-google-recaptcha for the recaptcha. I followed this blog post tutorial to add recaptcha in my app.
In local (my pc) recaptcha is working fine. But when i deploy to vercel i’m getting build error. I’ve attached error message below:
Type error: 'ReCAPTCHA' cannot be used as a JSX component.
Its type 'typeof ReCAPTCHA' is not a valid JSX element type.
Type 'typeof ReCAPTCHA' is not assignable to type 'new (props: any, deprecatedLegacyContext?: any) => Component<any, any, any>'.
Construct signature return types 'ReCAPTCHA' and 'Component<any, any, any>' are incompatible.
The types returned by 'render()' are incompatible between these types.
Type 'import("/vercel/path0/node_modules/@types/react-dom/node_modules/@types/react/index").ReactNode' is not assignable to type 'React.ReactNode'.
Type 'ReactElement<any, string | JSXElementConstructor<any>>' is not assignable to type 'ReactNode'.
Property 'children' is missing in type 'ReactElement<any, string | JSXElementConstructor<any>>' but required in type 'ReactPortal'.
128 | </div>
129 | <div className="formRow flex gap-6">
> 130 | <ReCAPTCHA
| ^
131 | size="normal"
132 | sitekey="6Ldh6jgoAAAAAM44ieDQ6Nw1cvAWa5i2NhGjpV4a"
133 | onChange={handleChange}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Command "yarn run build" exited with 1
I’ve also looked into the package documentation and couldn’t find the solution. Is my setup wrong or this package incompatible with next js typescript ? I would be thankful if anyone could point it out.