In this guide, we are going to look into Formspree - a service that grants us simple form submission handling. We will see how we can submit the form to Formspree using ES6 syntax in React.
When you are building static sites, you will come across numerous challenges surrounding how to deal with dynamic content, or form submissions. Well, perhaps you'd suggest for contact form submission that we can have a "mailto" link in the form action. We can, but that won't be an excellent experience for the user. The users will be required to switch into their email client and then they will also have to hit the send button- that's too much work to contact someone.
Formspree is the best service for static sites that don't have a backend to handle the form submissions. It is useful for portfolio sites and startups that don't want to invest much. Unlike other alternatives, like Google Form, we don't need to sacrifice the look of our website by embedding forms from external sources using an iframe that doesn't fit in with our User Interface (UI) for contact forms. We can make the form on our own that fits well with our site.
Formspree only requires us to have an action attribute that points to their URL. The URL format is https://formspree.io/{your email}
and all the forms will be submitted to your email. When the form is submitted for the first time, Formspree will send a confirmation email. Make sure that you confirm by clicking the link in the email to receive form submissions from your website.
1<form action="https://formspree.io/[email protected]" method="POST">
2 <div className="input-group">
3 <label htmlFor="email">E-mail Address</label>
4 <input
5 type="email"
6 name="email"
7 id="email"
8 value={this.state.values.email}
9 onChange={this.handleInputChange}
10 title="Email"
11 required
12 />
13 </div>
14 <div className="input-group">
15 <label htmlFor="message">Message</label>
16 <textarea
17 name="message"
18 id="message"
19 onChange={this.handleInputChange}
20 title="password"
21 required
22 >{this.state.values.message}</textarea>
23 </div>
24 <button type="submit">Send</button>
25</form>
For sending the form data using AJAX, we will have to add the submit handler and remove the action attribute.
1<form onSubmit={this.submitForm} >
2 ...
3 <button type="submit">Send</button>
4</form>
Like in my previous guide, Submit Form in React without jQuery AJAX we will have the state and handlers as follows:
1this.state = {
2 values: {
3 email: "",
4 message: ""
5 },
6 isSubmitting: false,
7 isError: false
8};
1handleInputChange = e =>
2 this.setState({
3 values: { ...this.state.values, [e.target.name]: e.target.value }
4 });
5
6submitForm = e => {
7 e.preventDefault();
8 // fetch() - post data to formspree url
9}
In my previous guide, we learned how we could submit form data using the fetch() API. For those of you who don't know what that is, it's the new Promise-based native method to make network requests.
1fetch(url, {...options})
2 .then(response => {
3 // resolve the data
4 })
5 .then(data => {
6 // use the data
7 });
For this guide, we will be using an external library - axios to make the network request for us.
The problem with fetch is that we require two steps to get the data and make use of it. Suppose, if we have to upload files, fetch won't get us the upload progress. So for such scenarios, we can use Axios.
Internally Axios uses the XML HTTP Request (XHR) and abstracts it's the complex syntax for us and provides a much cleaner method.
1axios.get(url, {...options})
2 .then(response => {
3 // handle success
4 })
5 .catch(error => {
6 // handle error
7 })
1axios.post(url, data, {...options})
2 .then(response => {
3 // handle success
4 })
5 .catch(error => {
6 // handle error
7 })
We can also use async/await with Axios:
1const getData = async () => {
2 try {
3 const {data} = await axios.get(url);
4 return data;
5 } catch(err) {
6 console.log(err);
7 }
8}
Now that we know about Axios and how to use its syntax, let's request the Formspree URL.
1submitForm = async e => {
2 e.preventDefault();
3 try {
4 const {data} = await axios.post("https://formspree.io/[email protected]", {...this.state.values});
5 } catch (err) {
6 console.log(err);
7 }
To summarise all the code above, here's the complete source for this guide.
1import React, { Component } from "react";
2import ReactDOM from "react-dom";
3
4import axios from "axios";
5
6import "./styles.css";
7
8class ContactForm extends Component {
9 constructor(props) {
10 super(props);
11 this.state = {
12 values: {
13 email: "",
14 message: ""
15 },
16 isSubmitting: false,
17 isError: false
18 };
19 }
20
21 submitForm = async e => {
22 e.preventDefault();
23 console.log(this.state);
24 this.setState({ isSubmitting: true });
25 try {
26 const {data} = await axios.post("https://formspree.io/[email protected]", {...this.state.values});
27 } catch (err) {
28 console.log(err);
29 }
30
31 setTimeout(
32 () =>
33 this.setState({
34 isError: false,
35 message: "",
36 values: { email: "", password: "" }
37 }),
38 1600
39 );
40 };
41
42 handleInputChange = e =>
43 this.setState({
44 values: { ...this.state.values, [e.target.name]: e.target.value }
45 });
46
47 render() {
48 return (
49 <div>
50 <form onSubmit={this.submitForm}>
51 <div className="input-group">
52 <label htmlFor="email">E-mail Address</label>
53 <input
54 type="email"
55 name="email"
56 id="email"
57 value={this.state.values.email}
58 onChange={this.handleInputChange}
59 title="Email"
60 required
61 />
62 </div>
63 <div className="input-group">
64 <label htmlFor="message">Message</label>
65 <textarea
66 name="message"
67 id="message"
68 onChange={this.handleInputChange}
69 title="password"
70 required
71 >{this.state.values.message}</textarea>
72 </div>
73 <button type="submit">Send</button>
74 </form>
75 <div className={`message ${this.state.isError && "error"}`}>
76 {this.state.isSubmitting ? "Submitting..." : this.state.message}
77 </div>
78 </div>
79 );
80 }
81}
82
83function App() {
84 return (
85 <div className="App">
86 <h1>Contact US</h1>
87 <ContactForm />
88 </div>
89 );
90}
91
92const rootElement = document.getElementById("root");
93ReactDOM.render(<App />, rootElement);
1.App {
2 font-family: sans-serif;
3}
4.input-group {
5 margin-bottom: 10px;
6}
7.input-group label {
8 display: block;
9 margin-bottom: 5px;
10}
11button {
12 border: none;
13 padding: 8px 24px;
14}
15.message {
16 margin-top: 20px;
17 font-weight: 600;
18}
19.message.error {
20 color: red;
21}
Unfortunately, Formspree doesn't allow AJAX calls to their URL and access to their API for free users. So, those users will have to make do with the action form attribute.
That's it from this guide. Until next time, keep hustling and code like a beast.