Last week, we looked at how to serialize form data into an object in vanilla JS. Today, we'll modify that helper function slightly so that it returns a JSON string instead. Let's start with the function from last week:

/**
* Serialize all form data into an object
* @param {HTMLFormElement} form The form to serialize
* @returns {Object} The serialized form data
*/

function serializeObject (form) {
// Create a new FormData object
const formData = new FormData(form);

// Create an object to hold the name/value pairs
const pairs = {};

// Add each name/value pair to the object
for (const [name, value] of formData) {
pairs[name] = value;
}

// Return the object
return pairs;
}

All we need to do is adjust the JSDoc block, rename the function, and add a call to the JSON.stringify() method at the end:

/**
* Serialize all form data into a JSON string
* @param {HTMLFormElement} form The form to serialize
* @returns {String} The serialized form data
*/

function serializeJSON (form) {
// Create a new FormData object
const formData = new FormData(form);

// Create an object to hold the name/value pairs
const pairs = {};

// Add each name/value pair to the object
for (const [name, value] of formData) {
pairs[name] = value;
}

// Return the JSON string
return JSON.stringify(pairs, null, 2);
}

Because I like my JSON strings to be nicely formatted, I used 2 as the third argument to the JSON.stringify() method. This means that the JSON string will be indented using two spaces. If you just want a minified JSON string, you can change it to JSON.stringify(pairs), omitting the other arguments.

This solution should work in all modern browsers, but not IE. I've made it available under the MIT license: serializeJSON.js.

If you need better backwards compatibility, you can use a modified version of my friend Chris Ferdinandi's serializeObject() helper function instead:

/**
* Serialize all form data into a JSON string
* (c) 2021 Chris Ferdinandi, MIT License, https://gomakethings.com
* @param {HTMLFormElement} form The form to serialize
* @returns {String} The serialized form data
*/

function serializeJSON (form) {
var obj = {};
Array.prototype.slice.call(form.elements).forEach(function (field) {
if (!field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) > -1) return;
if (field.type === 'select-multiple') {
var options = [];
Array.prototype.slice.call(field.options).forEach(function (option) {
if (!option.selected) return;
options.push(option.value);
});
if (options.length) {
obj[field.name] = options;
}
return;
}
if (['checkbox', 'radio'].indexOf(field.type) > -1 && !field.checked) return;
obj[field.name] = field.value;
});
return JSON.stringify(obj, null, 2);
}

This solution should work back to IE9. All I've done is rename the function, change it from a function expression to a function declaration, and return a JSON string instead of an object literal. Otherwise, it's Chris' original code.

View the demo on CodePen