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:
- Instantiate
new FormData(), passing the<form>element to its constructor. - Pass this
FormDataobject directly as thebodyof yourfetch()request. - Do not set the
Content-Typeheader yourself. The browser will automatically set it tomultipart/form-datawith 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:
- Create a
FormDataobject from the form. - Pass that
FormDataobject to thenew URLSearchParams()constructor. - Use the resulting
URLSearchParamsobject as thebodyof the request. - Again, do not set the
Content-Typeheader. 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:
- Create a
FormDataobject from the form. - Convert the
FormDataobject into a plain JavaScript object. - Use
JSON.stringify()to convert the object into a JSON string. - Set the
bodyof the request to this JSON string. - You must explicitly set the
Content-Typeheader 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
FormDatawhen your form includes file uploads. It's the most versatile but also has the largest request payload. - Use
URLSearchParamsfor simple, text-only forms. It is efficient and widely supported. - Use
JSON.stringify()when you are interacting with a modern API that expects anapplication/jsonrequest body.
For all methods involving FormData or URLSearchParams, remember to let the browser set the Content-Type header for you.