Creating a Fully Functional Contact Form with React and Formspree API
Published: 2023-02-23 14:54:00

A contact form is an essential component of any website, allowing visitors to reach out to you with their queries or feedback. In this tutorial, I will show you how to create a contact form with **Formspree API**,**React** and **Styled Components**. We will start with creating the basic form structure and styling it with **Styled Components**. Then we will integrate **Formspree API** to handle form submissions. [Formspree](https://formspree.io/) is a powerful and easy-to-use form back-end API that makes it simple to handle form submissions without any server-side coding. By the end of this tutorial, you'll have a working contact form that can send email notifications to your inbox whenever someone submits the form.
[Demo](https://react-contact-form.web.app/)
[Source Code](https://github.com/allenarduino/react-contact-form)

***Table of Contents:***

1. Prerequisites 
2. Setting Up the React Project
3. Creating the Form Page Layout
4. Creating The Details Bar Component
5. Creating The Input Side and Input Fields
6. Declaring The State Variables and Input Handler Functions
7. Creating a Formspree Account
8. Handling Form Submission
9. Creating The Success Page
10. Redirecting Users to The Success Page 
11. Conclusion

**Prerequisites:**
- Basic knowledge of React and JavaScript.
- A free Formspree account.  


**Setting Up The React Project:**
First, create a new React project using `create-react-app`. Open your terminal, navigate to your desired directory, and run the following command:
```
npx create-react-app react-contact-form
```
This will create a new React project with the name `react-contact-form`.
Once the project is created, navigate to the project root directory by running:
```
cd react-contact-form
```
We will be using `styled-components` for styling our components and `react-reveal` for fade-in animation.
Run the following command to install the dependencies:
```
npm i styled-components react-reveal
``` 

**Creating The Form Page Layout:**
Now that we have our project set up, let's create the page layout. In your project's `src` folder, create a new folder called `pages`. Navigate to the `pages` folder and create a new file called `FormPage.js`. Add the following code to the `FormPage.js`:

```js
//FormPage.js
import React from 'react';
import styled from 'styled-components';

const PageWrapper = styled.div`
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  align-items: center;
  background-color: whitesmoke;
  padding-bottom: 50px;
`;

const PageHeadingWrapper = styled.div`
  display: flex;
  flex-direction: column;
  margin-top: 40px;
`;

const FormContainer = styled.div`
  width: 70%;
  background-color: #fff;
  padding: 5px;
  border-radius: 5px;
  height: 70vh;
  @media (max-width: 768px) {
    width: 90%;
  }
`;

const TextOne = styled.b`
  font-size: 30px;
  color: rgb(4, 4, 59);
  text-align: center;
`;

const TextTwo = styled.p`
  color: rgb(4, 4, 34);
  font-size: 15px;
  text-align: center;
`;

const FormPage = () => {
  return (
    <PageWrapper>
      <PageHeadingWrapper>
        <TextOne>Contact US</TextOne>
        <TextTwo>Any Question or remarks? Just write us a message</TextTwo>
      </PageHeadingWrapper>
      <FormContainer></FormContainer>
    </PageWrapper>
  );
};

export default FormPage;

```
Now we get the output as shown below:



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2khy47ux1oq4fmjzc44b.png)

**Creating The Details Bar Component:**
In your project's `src` folder, create a new folder called `components`. Navigate to the `components` folder and create a new file called `DetailsBar.js`. Add the following code to the `DetailsBar.js`:

```js
//DetailsBar.js
import React from 'react';
import styled from 'styled-components';
import * as Icon from 'react-feather';

const DetailsBarWrapper = styled.div`
  background-color: rgb(8, 8, 63);
  border-radius: 7px;
  position: relative;
  padding: 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: auto;
  padding-bottom: 100px;
  @media (max-width: 768px) {
    padding-bottom: 80px;
    grid-row: 2;
  }
`;

const TextWrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
`;

const TextOne = styled.p`
  text-align: center;
  color: #fff;
  font-size: 18px;
  font-weight: bold;
`;

const TextTwo = styled.p`
  text-align: center;
  color: #fff;
  font-size: 12px;
  line-height: 18px;
`;

const BigCircle = styled.div`
  height: 50px;
  margin-top: 30px;
  width: 50px;
  background-color: rgb(100, 21, 173);
  border-radius: 100%;
  z-index: 22;
  margin-left: 10px;
`;

const SmallCircle = styled.div`
  position: absolute;
  margin-left: 10px;
  background-color: rgb(252, 113, 137);
  border-radius: 100%;
  height: 30px;
  width: 30px;
`;

const ContactsWrapper = styled.a`
  display: flex;
  width: 200px;
  height: 10px;
  margin-top: 50px;
  cursor: pointer;
  text-decoration: none;
`;

const ContactText = styled.div`
  color: #fff;

  font-size: 15px;
  margin-left: 10px;
`;

const SocialsWrapper = styled.div`
  display: flex;
  justify-content: center;
  display: flex;
  height: 10px;
  justify-content: center;
  bottom: 30px;
  position: absolute;
  cursor: pointer;
`;

const SocialIconWrapper = styled.a`
  width: 35px;
  height: 35px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  &:hover {
    background-color: rgb(252, 113, 137);
  }
`;

const DetailsBar = () => {
  return (
    <DetailsBarWrapper>
      <TextWrapper>
        <TextOne>Contact Information</TextOne>
        <TextTwo>Fill up the form and our team will get back to you within 24 hours</TextTwo>
      </TextWrapper>
      <div>
        <ContactsWrapper href="tel:+233543201893">
          <Icon.Phone size={15} color="rgb(252, 113, 137)" />
          <ContactText>+233543201893</ContactText>
        </ContactsWrapper>

        <ContactsWrapper href="mailto:aljay3334@gmail.com">
          <Icon.Mail size={15} color="rgb(252, 113, 137)" />
          <ContactText>aljay3334@gmail.com</ContactText>
        </ContactsWrapper>
      </div>

      <div>
        <BigCircle></BigCircle>
        <SmallCircle></SmallCircle>
      </div>

      <SocialsWrapper>
        <SocialIconWrapper href="https://www.facebook.com/profile.php?id=100021937291259">
          <Icon.Facebook color="#fff" size={20} />
        </SocialIconWrapper>
        <SocialIconWrapper href="https://www.instagram.com/_allenjones/">
          <Icon.Instagram color="#fff" size={20} />
        </SocialIconWrapper>
        <SocialIconWrapper href="https://www.linkedin.com/in/allen-jones-b799b7171/">
          <Icon.Linkedin color="#fff" size={20} />
        </SocialIconWrapper>
      </SocialsWrapper>
    </DetailsBarWrapper>
  );
};

export default DetailsBar;

```
In the `FormPage.js`, import the DetailsBar component into it as shown in the code below:

```js
//FormPage.js
import React from 'react';
import styled from 'styled-components';
import DetailsBar from '../components/DetailsBar';

const FormPage = () => {
  return (
    <PageWrapper>
      <PageHeadingWrapper>
        <TextOne>Contact US</TextOne>
        <TextTwo>Any Question or remarks? Just write us a message</TextTwo>
      </PageHeadingWrapper>
      <FormContainer>
        <DetailsBar />
      </FormContainer>
    </PageWrapper>
  );
};

export default FormPage;

```
The can now see the result in your browser as shown in the screenshot below:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irxxf7mvltkrkmtaio0o.png)

***Creating The Input Side:***
Let's create the input side and add input the fields. We will  style the input fields with styled components and make them responsive using CSS media queries. In the `components` folder, create a new file called `InputSide.js` and add the following code:
```js
//InputSide.js
import React from 'react';
import styled from 'styled-components';

const InputSideWrapper = styled.form`
  height: auto;
  padding-bottom: 100px;
  position: relative;
  padding: 10px 10px 100px 10px;
`;

const InputWrapper = styled.div`
  border: 2px solid transparent;
  width: 90%;
  padding-left: 10px;
  display: flex;
  flex-direction: column;
`;

const Input = styled.input`
  color: #333;
  width: 100%;
  font-size: 15px;
  padding: 8px;
  border-bottom: 1px solid rgb(100, 21, 173);
  border-left: 1px solid transparent;
  border-right: 1px solid transparent;
  border-top: 1px solid transparent;
  outline: 0px transparent !important;
`;

const MessageInput = styled.textarea`
  width: 100%;
  color: #333;
  font-size: 15px;
  padding: 10px;
  border-bottom: 1px solid rgb(100, 21, 173);
  border-left: 1px solid transparent;
  border-right: 1px solid transparent;
  border-top: 1px solid transparent;
  outline: 0px transparent !important;
`;

const SubMitButton = styled.input`
  position: absolute;
  bottom: 20px;
  right: 20px;
  padding: 10px;
  background-color: rgb(8, 8, 63);
  color: #fff;
  border: none;
  border-radius: 5px;
  padding: 12px 25px 12px 24px;
  cursor: pointer;
`;

const InputSide = () => {
  return (
    <InputSideWrapper>
      <InputWrapper>
        <p>Name</p>
        <Input type="text" placeholder="Allen Jones" />
      </InputWrapper>
      <InputWrapper>
        <p>Email</p>
        <Input type="email" placeholder="aljay126@gmail.com" />
      </InputWrapper>
      <InputWrapper>
        <p>Phone</p>
        <Input type="number" placeholder="+233546227893" />
      </InputWrapper>
      <InputWrapper>
        <p>Message</p>
        <MessageInput placeholder="Write your message" />
      </InputWrapper>
      <SubMitButton type="submit" value="Send Message" />
    </InputSideWrapper>
  );
};

export default InputSide;

```
  In the `FormPage.js`, import the InputSide component into it:

```js
//FormPage.js
import React from 'react';
import styled from 'styled-components';
import InputSide from '../components/InputSide';

const FormPage = () => {
  return (
    <PageWrapper>
      <PageHeadingWrapper>
        <TextOne>Contact US</TextOne>
        <TextTwo>Any Question or remarks? Just write us a message</TextTwo>
      </PageHeadingWrapper>
      <FormContainer>
        <DetailsBar />
        <InputSide/>
      </FormContainer>
    </PageWrapper>
  );
};

export default FormPage;

```
You can now see the result in your browser as shown in the screenshot below:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26semx6k7a8cebeg6mno.png)

**Declaring The State Variables and Input Handler Functions:**
Let's declare the state variables and also add the functions for handling the form inputs:

```js
//InputSide.js
const InputSide = () => {
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [phone, setPhone] = React.useState('');
  const [message, setMessage] = React.useState('');
  const [buttonLoading, setButtonLoading] = React.useState(false);

  const nameHandler = (e) => {
    setName(e.target.value);
  };

  const emailHandler = (e) => {
    setEmail(e.target.value);
  };

  const phoneHandler = (e) => {
    setPhone(e.target.value);
  };
  const messageHandler = (e) => {
    setMessage(e.target.value);
  };
};

export default InputSide;

```
In this code, we have used the useState hook to create state variables for the form inputs and the loading of the submit button. We have also add the input handler functions.

**Creating a Formspree Account :**
We will start by creating a free [Formspree acoount](https://formspree.io/).
Formspree offers multiple plans, including free and paid options, that cater to different submission volumes for your forms. The free plan allows for an unlimited number of forms and up to **50** monthly submissions.
To create a new form, log in to your Formspree account, access the dashboard, and click on the **New Form** button. Choose a memorable name for your form and click **Create Form.**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8ue6ri9jyzm5mreccpf.png)

You'll be taken to the form settings page. Under **Integrations** section, you'll see the endpoint URL. We will be using that for handling submissions. Kindly copy it.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0u0eet49nvk79a6kb0gd.png)

**Handling Form Submission:**
Let's add the function for handling submission:

```js
 const handleSubmit = async (e) => {
    e.preventDefault();
    const response = await fetch('https://formspree.io/f/<your-form-id>', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ name, email, phone, message }),
    });

    if (response.ok) {
      alert('Form Submitted');
    } else {
      alert('Failed to submit form');
    }
  };

```
In this code we used the `fetch` API to make a POST request to the Formspree endpoint.If the response from Formspree is successful, we'll handle it in the `if` block. Otherwise, we'll handle errors in the `else` block.

**Creating The Success Page:**
The success page is where users will be directed to after form submission. In `src/pages/` directory, create a new file called `SuccessPage.js`. Let's add this code to create and style the success page:

```js
//SuccessPage.js
import React from 'react';
import * as Icon from 'react-feather';
import { Fade } from 'react-reveal';
import styled from 'styled-components';

const MessageWrapper = styled.div`
  margin-top: 150px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
`;

const SuccessMessage = styled.h2`
  font-size: 25px;
  color: rgb(8, 8, 63);
  @media (max-width: 768px) {
    font-size: 18px;
  }
`;

const SuccessPage = () => {
  return (
    <React.Fragment>
      <Fade bottom duration={700} distance="60px">
        <MessageWrapper>
          <Icon.CheckCircle color="rgb(8, 8, 63)" style={{ width: 50, height: 50 }} />
          <SuccessMessage className="sucess-message">RESERVATION MADE SUCCESSFULLY</SuccessMessage>
        </MessageWrapper>
      </Fade>
    </React.Fragment>
  );
};

export default SuccessPage;

```
**Redirecting Users to The Success Page:**
We will be using `react-router-dom` to handle navigation between the two pages: The form page and the success page.
Run the following command in your terminal to install it:

```
npm install react-router-dom
```
Let's setup react router dom to handle navigation between the pages. Open `App.js` file in the src and replace the contents of the file with the following code:

```js
//App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import FormPage from './pages/FormPage';
import SuccessPage from './pages/SuccessPage';

const App = () => {
  return (
      <Router>
      <div>
        <Routes>
          <Route path="/" element={<FormPage />} />
          <Route path="/success" element={<SuccessPage />} />
        </Routes>
      </div>
    </Router>
  );
};

export default App;
```
In this code, we're importing `BrowserRouter`, `Route`, and `Routes` from `react-router-dom`. We also importing our `FormPage` and `SuccessPage` components.
We're using the `BrowserRouter` component wrap our routes. The `Route` component is used to define a route for a specific path.


We need to add a code in `InputSide.js` for redirecting user to the success page after submission.Open `InputSide.js` and add this code:

```js
import React from 'react';
import { useNavigate } from 'react-router-dom';
/***Previous Code***/

const InputSide = () => {

/***Previous Code***/

  const navigate = useNavigate();
  const handleSubmit = async (e) => {

/***Previous Code***/

    if (response.ok) {
      setButtonLoading(false);
      navigate('/success');
    } else {
      setButtonLoading(false);
      alert('Failed to submit form');
    }
  };

  
};

export default InputSide;
```

**Conclusion:**
In this tutorial, we learnt how to create a contact form in React using Formspree API and styled components. We also added `react-router-dom` for navigation between pages. With this knowledge, you can create and customize contact forms for your own projects.
[Demo](https://react-contact-form.web.app/)
[Source code](https://github.com/allenarduino/react-contact-form)