React Forms with Gatsby
In this guide we’ll show you how to add a contact form to your Gatsby website using Formspree.
Formspree is a form backend that’s an ideal companion for static site generators, letting you get on with building and deploying your Jamstack website.
At the end of this guide you should have a working React contact form in your Gatsby site that sends you email notifications. Check out a live demo of the final project. The project repository is hosted on GitHub.
Prerequisites
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 Gatsby. If you don’t have a Gatsby project yet, you can create one by running:
npx gatsby new gatsby-formspree-starter
cd gatsby-formspree-starter
npm run develop
If you’re not familiar with Gatsby then check out the official documentation to learn more.
Adding a form to Gatsby
Since Gatsby uses React, the form code you’re about to add can be neatly wrapped up in a React component.
Create a new file called contact-form.js
inside of your components
directory.
Here’s an example of the file structure including your new component:
project-root/
├─ gatsby-config.js
└─ src/
├─ components/
│ └─ contact-form.js
├─ pages/
└─ templates/
Next we’ll build the form component using a helper library from Formspree, @formspree/react
.
This library contains a useForm
hook to simplify the process of handling form submission events and managing form state.
Install it with:
npm install --save @formspree/react
Then paste the following code snippet into the contact-form.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} />
<label htmlFor="message">Message</label>
<textarea id="message" name="message" />
<ValidationError prefix="Message" field="message" errors={state.errors} />
<button type="submit" disabled={state.submitting}>
Submit
</button>
<ValidationError errors={state.errors} />
</form>
);
}
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 astate
object and ahandleSubmit
function which we pass to theonSubmit
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 nofield
attribute is provided).- For the sake of clarity, this form doesn’t include any styling, but in the github project (https://github.com/formspree/formspree-example-gatsby) you can see an example of how to apply styles to the form.
The component can now be imported into your website’s index page, or any page, like so:
import ContactForm from "../components/contact-form";
And inserted into the page as a React component:
<ContactForm />
Once you’ve saved your additions either run the Gatsby site locally with npm run develop
or deploy it to your live environment to see the newly added form.
At this point, when you attempt to submit the form, you’ll see an error message:
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 +New form 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.
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.
The code we used to create the contact-form.js
component is almost identical to the React example code on the integration page.
We just need to update the action
URL.
Finally copy the 8 character “hash id” from the new form’s endpoint URL and replace the YOUR_FORM_ID
placeholder in your contact form component.
const [state, handleSubmit] = useForm("abcd1234"); // <-- your form ID
Now when you fill out the form and submit, you should see a success message.
That’s it, you’re done!
Bonus Tip: Environment Variables
Sometimes you want to test out a new design locally, but don’t want to affect your production data. With Gatsby you can switch between development and production forms using environment variables.
In your contact-form.js
component, you can replace your form ID with an environment variable in your useForm
hook like so:
const [state, handleSubmit] = useForm(process.env.GATSBY_CONTACT_FORM);
Note: we must prefix the environment variable with GATSBY_
to ensure it’s accessible to front-end code.
Now create a .env.development
file at the root of your project with the following content:
GATSBY_CONTACT_FORM=xxxxxxxx
Replace xxxxxxxx
with your form’s hashid.
Now, as you’re working locally, your form will submit to the endpoint in your .env.development
file.
When you’re ready to ship to production, you can create a new production form in the Formspree dashboard, and set the GATSBY_CONTACT_FORM
variable to the new form id in production.
You can read more about how to use environment variables in Gatsby, and how to set build environment variables in Gatsby Cloud.