Rework Your Workweek: Join us in celebrating Matterday - how would you spend an extra day?

Guides & Tutorials

Build Contact Forms for Next.js Sites with Formspree

Guides & Tutorials

Build Contact Forms for Next.js Sites with Formspree

One of the most common obstacles to launching a Jamstack site is wiring up your forms to a backend server or function. “Why not just use Netlify Forms?” you ask. Definitely you can! However, for React projects, there are a few extra steps required to make sure the Netlify form parser identifies your form. Today we’ll be discussing an alternative, formspree-react, a form handling library built specifically for React projects.

Formspree-react provides a React-friendly useForm hook that handles form submits, updates the form state and displays server-side errors. As a bonus, once your form is connected to Formspree you can add plugins for Mailchimp, Google Sheets, and more with just a few clicks.

In this guide, we'll show you how to add a contact form to a Next.js website using Formspree and deploy it to Netlify. We’ll be using Next.js but the concepts can be applied to any React framework, such as Gatsby or Remix. At the end you should have a working React contact form in your Next.js project that sends you email notifications. You can find a demo of the final project at The project repository is hosted on github at


To follow this guide you're going to need a Formspree account, which you can sign up for free right here, and an existing web project built with Next.js. If you don't have a Next.js project yet, you can create one by running:

npx create-next-app <app-name>

If you're not familiar with Next.js then check out the official documentation to learn more.

Adding a form to Next.js

First, we're going to build a form component that you can place anywhere in your Next.js site. Create a new file called contactForm.js inside of your components directory. Here's an example of the file structure including your new component:

├─ components/
| └─ contactForm.js
└─ pages/
└─ index.js

Next we'll build the form component using @formspree/react. Install it with:

npm install --save @formspree/react

Then paste the following code snippet into the contactForm.js file:

import { useForm, ValidationError } from "@formspree/react";

export default function ContactForm() {
const [state, handleSubmit] = useForm("YOUR_FORM_ID");

if (state.succeeded) {
return <p>Thanks for your submission!</p>;

return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email Address</label>
<input id="email" type="email" name="email" />
<ValidationError prefix="Email" field="email" errors={state.errors} />

<textarea id="message" name="message" />
<ValidationError prefix="Message" field="message" errors={state.errors} />

<button type="submit" disabled={state.submitting}>
<ValidationError errors={state.errors} />

A few notes:

  • Currently the form contains a placeholder YOUR_FORM_ID. We'll replace this with our own form endpoint in a bit.
  • The useForm hook returns a state object and a handleSubmit function which we pass to the onSubmit form attribute. Combined, these provide a way to submit the form data via AJAX and update form state depending on the response received.
  • ValidationError components are helpers that display error messages for field errors, or general form errors (if no field attribute is provided).
  • For the sake of clarity, this form doesn't include any styling, but in the github project ( you can see an example of how to apply styles to the form.

The component can now be imported in your Next.js pages like so:

import ContactForm from "../components/contactForm";

And inserted into the page as a React component:

<ContactForm />

For this tutorial, we'll add the <ContactForm /> component to the bottom of our index.js file, but you can add it wherever you like!

Once you've saved your additions use your build or deployment workflow to either run the Next.js site locally or deploy it to where-ever you host your site (such as Netlify) to see the newly added form.

When you attempt to submit the form, you'll currently see an error message:

Error message from Formspree

Oops! We get an error because we still have the placeholder YOUR_FORM_ID in the form action. Let's fix this by setting up a form endpoint to accept our form submissions.

Creating a form endpoint

Next we'll create a form endpoint using Formspree. If you don't have an account yet you can sign up here.

To start, create a new form with the + button, call it Contact form and update the recipient email to the email where you wish to receive your form submissions. Then click Create Form.

Form dialogue box for Formspree creation

You'll then be presented with the integration options for your new Formspree form. Note that Formspree provides you with a wide range of implementation examples such as React, Ajax and regular HTML.

Integration Code for creating a React App with Formspree

The code we used to create the contactForm.js component is almost identical to the React example code on the integration page. We just need to update the useForm hook.

To do that, copy the 8 character "hash id" from the new form's endpoint URL and replace the YOUR_FORM_ID placeholder like so:

const [state, handleSubmit] = useForm("abcd1234"); // <-- your form hashid

Now when you fill out the form and submit, you should see a success message.

That's it, you're done!

Deploying to Netlify

To deploy this project to Netlify, create a new site and select “import an existing project”. Pick GitHub, and give Netlify access to your GitHub repositories. Select the appropriate repository.

If you’ve just been following along and don’t have a repository set up, you can just click the “Deploy to Netlify” button below!

deploy to netlify button

Bonus Tip: Production and Development Forms

Sometimes you want to test out a new design locally, but don't want to affect your production data. With Next.js you can switch between development and production forms using environment variables.

In your contactForm.js component, you can replace your form ID with an environment variable in your useForm hook like so:

const [state, handleSubmit] = useForm(process.env.NEXT_PUBLIC_FORM);

Now you need to ensure the variable is loaded when you develop locally. Create a .env.local file at the root of your project and add the environment variable, with your form’s hashid as the value:



  • In Next.js, only environment variables prefixed with NEXT_PUBLIC_ are accessible to client side javascript code. Don’t render secret environment variables, like API keys, into your frontend code.
  • Be sure to add your .env.local file to .gitignore so you don't accidentally check-in any secrets to version control. Your Formspree endpoint isn't secret, but nevertheless, it's a good practice.

Now, as you're working locally, your form will submit to the endpoint in your .env.local file. When you're ready to ship to production, create a new production form in the Formspree dashboard, and set the NEXT_PUBLIC_FORM environment variable to the new form endpoint in your hosting config (eg. Netlify).

You can read more about how to use environment variables in Next.js, and how to set build environment variables in Netlify.

Keep reading

Recent posts

Book cover with the title Deliver web project 10 times faster with Jamstack enterprise

Deliver web projects 10× faster

Get the whitepaper