Skip to main content

How to POST Form Data with the JavaScript Fetch API

Submitting form data to a server without a page reload is a cornerstone of modern web applications. The fetch() API provides a powerful and flexible way to send this data asynchronously. Depending on your needs—whether you're uploading files or just sending text—there are a few standard formats for the request body.

This guide will teach you the three primary methods for POSTing form data with fetch(): using a FormData object for file uploads, URLSearchParams for simple text data, and JSON for sending data to modern APIs.

The Setup: Capturing the Form submit Event

First, we need to capture the form's submit event. We'll attach an event listener that prevents the default browser behavior (a full-page refresh) and then executes our fetch() request.

HTML:

<form id="login-form">
<input type="text" id="username" name="username" required>
<input type="password" id="password" name="password" required>
<button type="submit">Log In</button>
</form>

JavaScript:

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

form.addEventListener('submit', function (event) {
// Prevent the default form submission
event.preventDefault();

// (Our fetch logic will go here)
});

All subsequent examples will be placed inside this event listener.

Method 1: Using FormData (for files and complex data)

The FormData object is the ideal choice when your form includes file uploads (<input type="file">) or when you need to send a mix of data types. It mimics a standard form submission with an encoding type of multipart/form-data.

The logic:

  1. Instantiate new FormData(), passing the <form> element to its constructor.
  2. Pass this FormData object directly as the body of your fetch() request.
  3. Do not set the Content-Type header yourself. The browser will automatically set it to multipart/form-data with the correct boundary.

Solution:

form.addEventListener('submit', async function (event) {
event.preventDefault();

const formData = new FormData(form);

try {
const response = await fetch('https://api.example.com/login', {
method: 'POST',
body: formData,
});

const result = await response.json();
console.log('Success:', result);
} catch (error) {
console.error('Error:', error);
}
});

Method 2: Using URLSearchParams (for simple text data)

When your form contains only simple text fields (no files), using URLSearchParams is often more efficient. It formats the data with the application/x-www-form-urlencoded content type, which is a standard way to send key-value pairs.

The logic:

  1. Create a FormData object from the form.
  2. Pass that FormData object to the new URLSearchParams() constructor.
  3. Use the resulting URLSearchParams object as the body of the request.
  4. Again, do not set the Content-Type header. The browser will set it correctly.

Solution:

form.addEventListener('submit', async function (event) {
event.preventDefault();

const formData = new FormData(form);
const searchParams = new URLSearchParams(formData);

// The body will look like: username=test&password=123
console.log(searchParams.toString());

try {
const response = await fetch('https://api.example.com/login', {
method: 'POST',
body: searchParams,
});

const result = await response.json();
console.log('Success:', result);
} catch (error) {
console.error('Error:', error);
}
});

Method 3: Sending Data as JSON (for modern APIs)

Many modern web APIs are designed to receive data in JSON format (application/json). This method requires a bit more manual work but is extremely common.

The logic:

  1. Create a FormData object from the form.
  2. Convert the FormData object into a plain JavaScript object.
  3. Use JSON.stringify() to convert the object into a JSON string.
  4. Set the body of the request to this JSON string.
  5. You must explicitly set the Content-Type header to 'application/json'.

Solution:

form.addEventListener('submit', async function (event) {
event.preventDefault();

const formData = new FormData(form);
const formObject = Object.fromEntries(formData.entries());

try {
const response = await fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formObject),
});

const result = await response.json();
console.log('Success:', result);
} catch (error) {
console.error('Error:', error);
}
});

Conclusion

The fetch() API provides several powerful ways to submit form data, and the best method depends on the requirements of your server-side endpoint.

  • Use FormData when your form includes file uploads. It's the most versatile but also has the largest request payload.
  • Use URLSearchParams for simple, text-only forms. It is efficient and widely supported.
  • Use JSON.stringify() when you are interacting with a modern API that expects an application/json request body.

For all methods involving FormData or URLSearchParams, remember to let the browser set the Content-Type header for you.