POST form data using JavaScript’s Fetch API

Reading Time: 3 minutes 🕑

Last updated: August 24, 2022.

Using JavaScript’s Fetch API to send form data gives you full control of data transmission.

Rather than relying on standard HTML behavior, which immediately sends the data payload upon submit and redirects to a new page, you can handle the data transmission in the background and communicate the result efficiently through minimal DOM manipulation.

Best of all, this process is made extremely easy by in-built constructor objects in JavaScript that do most of the heavy lifting.

Table of contents

Prerequisites

Form setup

To demonstrate, we need a form.

Let’s keep things simple: a form with an id of form with which we can select it in JavaScript. The form contains two input fields named username and password. Make sure to give the inputs identifiable names because these will be the keys through which data values can be identified in the payload.

Finally, there is a button of type submit that will submit the form data as a submit event.

<!--- HTML form data --->

<form id="form">
    <input name="username" type="text">
    <input name="password "type="password">
    <button type="submit">Submit</button>
</form> 

Add a form submit event listener

First, select the form element and add an event listener to it, listening out for a submit event. And inside the function, apply the preventDefault() method to the event object to prevent the form being submitted by HTML by default.

/* Selecting the HTML form and adding a 'submit' event listener */

const form = document.getElementById('form');

form.addEventListener('submit', function(e) {
    e.preventDefault()
})

Sending the form data

Option #1: As FormData object

The in-built FormData object constructor will help you do all the heavy lifting.

Pass in a form element to it, and it will convert its contents into arrays of data (one for each form element) containing two items: an element’s name attribute and the value input for the element.

Because the object produced is a special FormData object with associated methods, you cannot view its payload contents directly with console.log(). Instead, access the contained data directly using console.log([…payload]).

/* Converting the form to a new formData object */

const form = document.getElementById('form');

form.addEventListener('submit', function(e) {
    // Prevent default behavior:
    e.preventDefault();
    // Create payload as new FormData object:
    const payload = new FormData(form);
    console.log([…payload]);
})

Now, you can send the form data as a POST request using the Fetch API. We use the test server httpbin.org to make the request. It responds by sending back the request’s parameters, which is fine for testing purposes.

Importantly, do not create a Content-Type property in the options object passed in to the fetch request in the second position. This will be determined automatically as multipart/form-data (the norm for HTML forms). Entering an erroneous value could lead to an error.

/* Sending the formData object as payload using Fetch */

const form = document.getElementById('form');

form.addEventListener('submit', function(e) {
    // Prevent default behavior:
    e.preventDefault();
    // Create payload as new FormData object:
    const payload = new FormData(form);
    // Post the payload using Fetch:
    fetch('https://httpbin.org/post', {
    method: 'POST',
    body: payload,
    })
    .then(res => res.json())
    .then(data => console.log(data))
})

Option #2: As a URL-enconded string

You can also send the form data as a URL-encoded string. This i more efficient for text-based form data.

For this, you can also lean heavily on an in-built object constructor: URLSearchParams. Pass in a FormData object, and it will convert it to a URL-encoded string that you can then send as the payload.

/* Converting the form to a URL-encoded string */

const form = document.getElementById('form');

form.addEventListener('submit', function(e) {
    // Prevent default behavior
    e.preventDefault();
    // Create new FormData object:
    const formData = new FormData(form);
    // Convert formData object to URL-encoded string:
    const payload = new URLSearchParams(formData);
})

The fetch request to send the payload is exactly the same as above. But this time, it will be sent as content type application/x-www-form-urlencoded. You do not need to enter a Content-Type property, as this will be set automatically.

/* Sending the URL-encoded string as payload using Fetch */

const form = document.getElementById('form');

form.addEventListener('submit', function(e) {
    // Prevent default behavior:
    e.preventDefault();
    // Create new FormData object:
    const formData = new FormData(form);
    // Convert formData object to URL-encoded string:
    const payload = new URLSearchParams(formData);
    // Post the payload using Fetch:
    fetch('https://httpbin.org/post', {
    method: 'POST',
    body: payload,
    })
    .then(res => res.json())
    .then(data => console.log(data))
})

For this type of payload, the browser will decode what is sent for you to view it in developer tools. For this, access (in Chrome) the Network > Fetch/XHR. Now select the post item in this view and view the Payload tab. It should look something like this:

View the payload in the browser

Summary

Using JavaScript's Fetch API to submit form data gives you full flexibility over the data transmission process, rather than relying upon the default form submission behavior of HTML.

Related links