- Published on
Create a Contact Form with Formspree in a Next.js Project
- Authors
- Name
- Code Smarter
- @codesmarter_dev
📨 Introduction
When your Next.js site is static (like on Vercel), there’s no backend available to handle contact form submissions.
That’s where Formspree comes in — it lets you receive messages from your visitors directly via email, without writing a single line of backend code.
Formspree’s official useForm
hook simplifies the entire process: it handles form submission, loading states, and errors for you.
In this tutorial, we’ll:
- Install the official
@formspree/react
package - Create a styled and responsive contact form
- Deploy it on Vercel
⚙️ 1. Install the Formspree package
First, install the official React package:
npm install @formspree/react
✉️ 2. Create your Formspree account
Go to formspree.io
Click Start for free
Once logged in, create a new form
You’ll get a unique form endpoint, for example:
https://formspree.io/f/mayvpqdr
Keep the Formspree ID (mayvpqdr) — you’ll need it in the next step.
🧩 3. Create the form using useForm
Create a component: components/ContactForm.jsx
"use client";
import { useForm, ValidationError } from "@formspree/react";
export default function ContactForm() {
const [state, handleSubmit] = useForm("mayvpqdr"); // Replace with your Formspree ID
if (state.succeeded) {
return (
<p className="text-green-600 text-center font-medium">
✅ Message successfully sent!
</p>
);
}
return (
<form
onSubmit={handleSubmit}
className="mx-auto max-w-md space-y-4 p-6 rounded-xl border border-gray-200 dark:border-gray-700 shadow-md"
>
<div>
<label htmlFor="email" className="block font-medium mb-1">
Email address
</label>
<input
id="email"
type="email"
name="email"
required
className="w-full rounded-md border border-gray-300 p-2 dark:bg-gray-800 dark:border-gray-600"
/>
<ValidationError prefix="Email" field="email" errors={state.errors} />
</div>
<div>
<label htmlFor="message" className="block font-medium mb-1">
Message
</label>
<textarea
id="message"
name="message"
rows="5"
required
className="w-full rounded-md border border-gray-300 p-2 dark:bg-gray-800 dark:border-gray-600"
/>
<ValidationError prefix="Message" field="message" errors={state.errors} />
</div>
<button
type="submit"
disabled={state.submitting}
className="w-full rounded-md bg-primary-600 p-2 text-white hover:bg-primary-700 transition"
>
{state.submitting ? "Sending..." : "Send"}
</button>
</form>
);
}
🧱 4. Create the /contact page
Create a file at app/contact/page.jsx:
import ContactForm from "@/components/ContactForm";
export default function ContactPage() {
return (
<section className="py-12 px-6">
<h1 className="text-3xl font-bold mb-6 text-center">Contact</h1>
<p className="text-center text-gray-500 mb-8">
Have a question or a collaboration idea? Drop me a message 👇
</p>
<ContactForm />
</section>
);
}
🏁 Conclusion
And that’s it 🎉 In just a few lines, you now have a fully functional React contact form that works perfectly on Vercel, without any backend, and with built-in error handling through the useForm hook.