Skip to content
recaptcha-next

Contact form

A form that verifies a visitor with a Server Action and shows the result. This is the shape the package is tested with in a real Next.js app.

The form

// app/ContactForm.tsx
"use client";

import { useActionState } from "react";
import { RecaptchaField } from "recaptcha-next/client";
import { submitAction } from "./actions";

export function ContactForm({ lazy = false }: { lazy?: boolean }) {
  const [state, formAction] = useActionState(submitAction, { success: null, reason: null });
  return (
    <form action={formAction}>
      <input name="message" />
      <RecaptchaField action="contact" lazy={lazy} />
      <button type="submit">Send</button>
      {state.success === false && <p role="alert">{state.reason}</p>}
    </form>
  );
}

The Server Action

// app/actions.ts
"use server";

import { getRecaptchaToken, verifyRecaptcha } from "recaptcha-next/server";

export async function submitAction(_previous: unknown, formData: FormData) {
  const result = await verifyRecaptcha(getRecaptchaToken(formData), {
    expectedAction: "contact",
    expectedHostname: "example.com",
  });
  return { success: result.success, reason: result.success ? null : result.reason };
}

Pass lazy to wait for the viewport, see Lazy loading. The environment needs NEXT_PUBLIC_RECAPTCHA_SITE_KEY and RECAPTCHA_SECRET_KEY.