1

I'm building a new portfolio site and I want it to have a contact form. The project is built with React and I had planned on using Formspree to add a contact form without a backend. Turns out Formspree no longer allows AJAX calls unless you're a paid subscriber.

Are there any alternatives for contact forms similar to Formspree? I had planned to do something like this but can't due to Formspree's limitations.

I know very little about backend programming and would prefer not to have to dive into Node/Express just for the sake of hooking up a contact form. Is this practical or would just adding a backend be easier at this point?

Nick Kinlen
  • 1,356
  • 4
  • 30
  • 58

3 Answers3

6

Hello you can use formcarry for this purpose.

Here is an example code for you:

import React from "react";
import axios from "axios"; // For making client request.


class Form extends React.Component {
  constructor(props){
    super(props);
    this.state = {name: "", surname: "", email: "", message: ""};
  }

  handleForm = e => {
    axios.post(
      "https://formcarry.com/s/yourFormId", 
      this.state, 
      {headers: {"Accept": "application/json"}}
      )
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });

    e.preventDefault();
  }

  handleFields = e => this.setState({ [e.target.name]: e.target.value });

  render() {
    return (
      <form onSubmit={this.handleForm}>
        <label htmlFor="name">Name</label>
        <input type="text" id="name" name="name" onChange={this.handleFields} />

        <label htmlFor="surname">Surname</label>
        <input type="text" id="surname" name="surname" onChange={this.handleFields} />

        <label htmlFor="email">Email</label>
        <input type="email" id="email" name="email" onChange={this.handleFields} />

        <label htmlFor="message">Your Message</label>
        <textarea name="message" id="message" onChange={this.handleFields}></textarea>

        <button type="submit">Send</button>
      </form>
    );
  }
}

export default Form;
nusu
  • 364
  • 1
  • 4
  • 15
  • Thanks! This is a simple replacement for Formspree that is AJAX friendly and free. – Nick Kinlen Sep 28 '18 at 01:31
  • How do you clear the values and display the success message once the form is sent? – JackJack Jan 17 '19 at 14:35
  • @Ang response object includes success or warning messages, while Formcarry returns errors with status codes Axios handle them in catch method, you can inspect it with console.log(error.response.data), For clearing the input fields I recommend using state in input's value like `value={this.state.name}` and if you clear states, it will automatically reset the values thanks to reactivity – nusu Jan 22 '19 at 13:05
4

As of Nov 2019 Formspree supports AJAX forms on the free plan. They recently did a 3 part tutorial series on building forms with React using Formspree for the examples. See: https://formspree.io/blog/react-forms-1/

Here's a snippet of code from part 3 of the above series. It's a simple contact for that performs client-side validation with Formik.

    import React, { useState } from "react";
    import axios from "axios";
    import { Formik, Form, Field, ErrorMessage } from "formik";
    import * as Yup from "yup";

    const formSchema = Yup.object().shape({
      email: Yup.string()
        .email("Invalid email")
        .required("Required"),
      message: Yup.string().required("Required")
    });

    export default () => {
      /* Server State Handling */
      const [serverState, setServerState] = useState();
      const handleServerResponse = (ok, msg) => {
        setServerState({ok, msg});
      };
      const handleOnSubmit = (values, actions) => {
        axios({
          method: "POST",
          url: "http://formspree.io/YOUR_FORM_ID",
          data: values
        })
          .then(response => {
            actions.setSubmitting(false);
            actions.resetForm();
            handleServerResponse(true, "Thanks!");
          })
          .catch(error => {
            actions.setSubmitting(false);
            handleServerResponse(false, error.response.data.error);
          });
      };
      return (
        <div>
          <h1>Contact Us</h1>
          <Formik
            initialValues={{ email: "", message: "" }}
            onSubmit={handleOnSubmit}
            validationSchema={formSchema}
          >
            {({ isSubmitting }) => (
              <Form id="fs-frm" noValidate>
                <label htmlFor="email">Email:</label>
                <Field id="email" type="email" name="email" />
                <ErrorMessage name="email" className="errorMsg" component="p" />
                <label htmlFor="message">Message:</label>
                <Field id="message" name="message" component="textarea" />
                <ErrorMessage name="message" className="errorMsg" component="p" />
                <button type="submit" disabled={isSubmitting}>
                  Submit
                </button>
                {serverState && (
                  <p className={!serverState.ok ? "errorMsg" : ""}>
                    {serverState.msg}
                  </p>
                )}
              </Form>
            )}
          </Formik>
        </div>
      );
    };
Cole
  • 2,933
  • 2
  • 18
  • 10
0

As an update in 2021 (not sure when it was introduced or changed) the standard react approach for formspree does not do any redirect and hides any AJAX details from you.

They have more info here - correct at tine of writing but worth checking as it updates quite regularly: https://help.formspree.io/hc/en-us/articles/360053108134-How-To-Build-a-Contact-Form-with-React

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

function ContactForm() {
  const [state, handleSubmit] = useForm("contactForm");
  if (state.succeeded) {
      return <p>Thanks for joining!</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}>
        Submit
      </button>
    </form>
  );
}
export default ContactForm;

There are a few extra steps which are contained in the page above but this is the main contact from function

Mick
  • 24,231
  • 1
  • 54
  • 120