DEV Community

Cover image for Creating a Fully Functional Contact Form with React and Formspree API
Allen Jones
Allen Jones

Posted on • Edited on

Creating a Fully Functional Contact Form with React and Formspree API

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 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
Source Code

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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:



//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;



Enter fullscreen mode Exit fullscreen mode

Now we get the output as shown below:

Image description

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:



//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;



Enter fullscreen mode Exit fullscreen mode

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



//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;



Enter fullscreen mode Exit fullscreen mode

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

Image description

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:



//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;



Enter fullscreen mode Exit fullscreen mode

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



//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;



Enter fullscreen mode Exit fullscreen mode

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

Image description

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



//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;



Enter fullscreen mode Exit fullscreen mode

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.
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

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

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



 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');
    }
  };



Enter fullscreen mode Exit fullscreen mode

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:



//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;



Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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:



//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;


Enter fullscreen mode Exit fullscreen mode

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:



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;


Enter fullscreen mode Exit fullscreen mode

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
Source code

Top comments (2)

Collapse
 
latifissaka profile image
Pheel_official

Thanks for this, Allen.

Collapse
 
allenarduino profile image
Allen Jones

You're welcome