Dec 16

FormData API

The FormData API allows serializing form fields and provides methods to get, set, and update values.

By Chris Ferdinandi

Historically, getting all of the data from a form into a single object was a bit difficult, but modern techniques make it a lot easier.

Let’s dig in!

Creating a FormData object

The FormData object provides an easy way to serialize form fields into key/value pairs.

You can use the new FormData() constructor to create a new FormData object, passing in the form to serialize as an argument. 

For example, let’s imagine you have a form that looks like this.

<form>
<label for="title">Title</label>
<input type="text" name="title" id="title" value="Go to the beach">

<label for="body">Body</label>
<textarea id="body" name="body">Soak up the sun and swim in the ocean.</textarea>

<input type="hidden" name="userId" value="1">
<button>Submit</button>
</form>

To create a FormData object, you would pass the form into the new FormData() constructor, like this.

// Get the form
let form = document.querySelector('form');

// Get all field data from the form
// returns a FormData object
let data = new FormData(form);

The FormData object is an iterable.

You can loop through it using a for...of loop. Each entry is an array of key/value pairs.

// logs...
// ["title", "Go to the beach"]
// ["body", "Soak up the sun and swim in the ocean."]
// ["userId", "1"]

for (let entry of data) {
console.log(entry);
}

Here’s a demo for you to play with.

You can also use array destructuring to assign the key and value to their own variables within the for...of loop.

// logs "title", "Go to the beach", etc.

for (let [key, value] of data) {
console.log(key);
console.log(value);
}

Here’s another demo, with array destructuring.

Getting, setting, and updating FormData values

The FormData object has a handful of methods that you can use to get, set, and update values.

The FormData.get() method accepts the name of the field as an argument and returns its value. Here, we would get the value of the [name="title"] field.

// returns "Go to the beach"
let title = data.get('title');

If you had multiple fields with the same name, you might instead use the FormData.getAll() method. It returns an array of values instead.

// returns ["Go to the beach"]
let titles = data.getAll('title');

You can use the FormData.set() method to add a new value to your FormData object. If an entry with that name already exists, the FormData.set() method overwrites it.

Pass in a name and value as arguments.

// Add a new entry, "date", to the FormData object
data.set('date', '2022-12-25');

// Overwrite the "id" entry
data.set('id', '42');

The FormData.append() method adds an additional value for an existing entry if one with that name already exists. If not, it creates a new entry.

Pass in a name and value as arguments.

// Adds an additional "id" value
data.append('id', '123');

// Creates a new entry, "tags"
data.append('tags', 'vacations');

The FormData.delete() method deletes all values for an entry.

Pass in the name of the item to delete as an argument.

// Deletes the "body" entry
data.delete('body');

Here’s a demo with all of the methods for manipulating FormData values.

It’s worth noting that all of these changes happen to the FormData object and its values, not the actual form element or its fields.

None of these methods will update the state of the DOM or UI.

Convenience methods

The FormData object also provides a few convenient methods for working with form data.

The FormData.has() method can be used to check if a FormData object contains an entry with a specific name.

It returns a boolean: true if the entry exists and false if it does not.

// returns true
let hasID = data.has('id');

The FormData.keys() method returns an iterator with all of the keys in the FormData object.

You can loop them with a for…of loop, or convert them into an array using the Array.from() method.

// Loop through all keys
for (let key of data.keys()) {
console.log(key);
}

// Convert to an array
let arr = Array.from(data.keys());

Here’s a demo of the FormData.keys() method.

The FormData.values() method returns an iterator with all of the values in the FormData object.

// Loop through
for (let val of data.values()) {
console.log(val);
}

// Convert to an array
let arr = Array.from(data.values());

Here’s a demo of the FormData.values() method.

Serializing FormData into an object

You might intend to pass your FormData object along to an API.

While some APIs will accept a FormData object in its native form, many require you to pass along an object instead.

If your form does not contain multiple fields with the same name, you can use the Object.fromEntries() method to convert your FormData object into a plain object ({}).

// returns...
// {
// title: "Go to the beach",
// body: "Soak up the sun and swim in the ocean",
// id: "1"
// }

let serialized = Object.fromEntries(data);

However, if your form has multiple fields with the same name, only the value of the last field with that name will appear in the object.

We instead need to loop through each entry with a for...of loop and add it to an object.

let obj = {};

for (let [key, value] of data) {
obj[key] = value;
}

To account for multiple fields with the same name, we need to check if the key already exists in the obj. 

If it does, we want to convert it to an array and Array.push() the new value into it.

let obj = {};

for (let [key, value] of data) {
if (obj[key] !== undefined) {
if (!Array.isArray(obj[key])) {
obj[key] = [obj[key]];
}

obj[key].push(value);
} else {
obj[key] = value;
}
}

If you find yourself doing this often, I’ve put together a helper method you can use.

Once you have your object, you can pass it into the JSON.stringify() method to send along to an API.

let stringified = JSON.stringify(obj);

Serializing FormData into a query string

Some APIs instead require data as a query string.

let str = 'key=some+value&another-key=some+other+value';

To convert our FormData object into a query string, we’ll use the URLSearchParams()

It provides methods for getting, setting, and modifying query string values and has a similar API as the FormData object.

First, we’ll use the new URLSearchParams() constructor to create our query string object.

let params = new URLSearchParams();

Next, we’ll loop through each item in our FormData object with a for…of loop, and use the URLSearchParams.append() method to add the key and val to our query string.

The URLSearchParams.append() method automatically encodes the value for us.

for (let [key, val] of data) {
params.append(key, val);
}

Finally, we can use the URLSearchParams.toString() method to get the actual query string.

let str = params.toString();

Here’s a demo of the URLSearchParams object.

Wrapping up

We covered a lot in this article, so let’s quickly wrap up what we learned.

If you enjoyed this, you might also like my Daily Developer Tips newsletter. Each weekday, I send out a short email on how to build a simpler, more resilient web.

Chris selected Feeding America for an honorary donation of $50 which has been matched by Netlify

Feeding America

Feeding America is the largest charity working to end hunger in the United States. We partner with food banks, food pantries, and local food programs to bring food to people facing hunger. We advocate for policies that create long-term solutions to hunger.