Forms & Serialization
Forms are where users give you data: registrations, orders, feedback, search. With JavaScript you can check the data before it is sent, send it without reloading the page, and show the result in place. jQuery made this popular with two methods that turn a whole form into data in one line: .serialize() and .serializeArray().
In this lesson you will handle the submit event correctly, serialize forms, send them with AJAX, validate them using the browser's built-in rules, and see the modern equivalents: FormData, URLSearchParams and fetch().
Handle submit, not click
Listen for the form's submit event, not the button's click. Submit also fires when someone presses Enter in a text field, and it is where the browser's validation happens. Call event.preventDefault() to stop the normal page reload, then do your own work:
$("#signup").on("submit", function (event) {
event.preventDefault();
const data = $(this).serialize();
// ...send data with AJAX
});
// Plain JavaScript
document.querySelector("#signup").addEventListener("submit", (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
});serialize() and serializeArray()
.serialize() turns a form into a URL-encoded string, the same format a browser sends for a normal form: name=Meera%20K&city=Kochi. .serializeArray() gives an array of { name, value } objects instead.
Both include only successful controls, the same ones a real form submission would send:
- the control must have a
nameattribute; - it must not be
disabled; - checkboxes and radio buttons only when they are checked;
- file inputs and the submit button are left out.
Fill in this form and submit it to compare jQuery's output with the modern API:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Serializing a form</title>
<style>
form { display: grid; gap: 0.5rem; max-inline-size: 26rem; }
pre { background: #f3f5f7; padding: 0.5rem; white-space: pre-wrap; word-break: break-all; }
</style>
</head>
<body>
<form id="admission">
<label>Name <input name="name" value="Meera Krishnan" required></label>
<label>City
<select name="city">
<option>Jaipur</option>
<option selected>Kochi</option>
<option>Pune</option>
</select>
</label>
<fieldset>
<legend>Subjects</legend>
<label><input type="checkbox" name="subjects" value="Maths" checked> Maths</label>
<label><input type="checkbox" name="subjects" value="Biology"> Biology</label>
<label><input type="checkbox" name="subjects" value="Computer Science" checked> Computer Science</label>
</fieldset>
<label>Admission number (filled by office) <input name="admNo" value="A-1042" disabled></label>
<button>Submit</button>
</form>
<h4>jQuery .serialize()</h4>
<pre id="s1"></pre>
<h4>jQuery .serializeArray()</h4>
<pre id="s2"></pre>
<h4>Plain: URLSearchParams(FormData) and getAll()</h4>
<pre id="s3"></pre>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
$("#admission").on("submit", function (event) {
event.preventDefault();
$("#s1").text($(this).serialize());
$("#s2").text(JSON.stringify($(this).serializeArray()));
const formData = new FormData(this);
$("#s3").text(
new URLSearchParams(formData).toString() + "\n" +
"subjects: " + JSON.stringify(formData.getAll("subjects"))
);
});
</script>
</body>
</html>The disabled admission number and the unticked subject are missing in every version. Spaces appear as %20 in jQuery's string and + in URLSearchParams; servers read both the same way.
Turning form data into an object
Neither serialize method gives you a simple object. Use the array, or FormData with Object.fromEntries(). Watch out for fields that can have several values, like the subjects checkboxes:
// jQuery
const obj = {};
$.each($("#admission").serializeArray(), function (i, field) {
if (field.name in obj) obj[field.name] = [].concat(obj[field.name], field.value);
else obj[field.name] = field.value;
});
// Plain JavaScript
const formData = new FormData(document.querySelector("#admission"));
const data = Object.fromEntries(formData); // keeps only the LAST value of "subjects"
data.subjects = formData.getAll("subjects"); // so read multi-value fields with getAll()The reverse of .serialize() is $.param(object), which builds a query string from an object. By default it adds [] to array names (subjects%5B%5D=Maths), the format PHP expects; pass true as the second argument for the plain subjects=Maths&subjects=CS style.
Sending a form with AJAX
$.post() with .serialize() sends exactly what a normal form submit would, so the server code does not need to change. The modern version passes the form data to fetch():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AJAX form</title>
</head>
<body>
<form id="feedback" action="https://jsonplaceholder.typicode.com/posts" method="post">
<label>Your name <input name="name" value="Farhan" required></label><br>
<label>Rating
<select name="rating"><option>5</option><option>4</option><option>3</option></select>
</label><br>
<label>Comment <input name="comment" value="Clean classrooms in the Lucknow centre"></label><br>
<button name="via" value="jquery">Send with jQuery</button>
<button name="via" value="fetch">Send with fetch</button>
</form>
<p id="result"></p>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
$("#feedback").on("submit", async function (event) {
event.preventDefault();
const form = this;
const via = event.originalEvent.submitter.value; // which button was pressed
$(form).find("button").prop("disabled", true);
$("#result").text("Sending...");
try {
let saved;
if (via === "jquery") {
saved = await $.post(form.action, $(form).serialize());
} else {
const response = await fetch(form.action, { method: "POST", body: new URLSearchParams(new FormData(form)) });
if (!response.ok) throw new Error("HTTP " + response.status);
saved = await response.json();
}
$("#result").text("Saved by " + via + " as #" + saved.id + ": " + saved.name + " gave " + saved.rating + " stars");
} catch (error) {
$("#result").text("Could not send feedback.");
} finally {
$(form).find("button").prop("disabled", false);
}
});
</script>
</body>
</html>event.submitter (reached through originalEvent in jQuery) tells you which submit button was used. Reading form.action keeps the URL in the HTML, so the form still has a sensible target if JavaScript fails to load.
Validating with the browser's rules
Before writing validation code, use HTML attributes: required, type="email", minlength, min, max and pattern. The browser checks them on submit and shows messages in the user's language. JavaScript can ask for the result:
const form = document.querySelector("#signup");
form.checkValidity(); // true or false, no messages shown
form.reportValidity(); // true or false, and shows the browser's messages
const phone = form.elements.phone;
phone.setCustomValidity(/^[6-9]\d{9}$/.test(phone.value) ? "" : "Enter a 10-digit Indian mobile number");setCustomValidity("") marks the field valid again; any other text marks it invalid with that message. In jQuery code you will often see the jQuery Validation plugin doing this job; covered in Using & Writing Plugins.
Common mistakes
- Listening to the button's click instead of the form's submit. Pressing Enter skips your code and the page reloads.
- Forgetting the
nameattribute. Fields without a name are left out of.serialize()andFormData. - Expecting disabled fields to be sent. Use
readonlyfor values the user must not edit but the server needs. - Using
Object.fromEntries(formData)with multi-value fields. Only the last value survives; usegetAll(). - Trusting client-side checks. Anyone can bypass JavaScript. The server must validate again.
Key points
- Handle the form's
submitevent and callevent.preventDefault(). .serialize()gives a URL-encoded string and.serializeArray()an array of{ name, value }; only named, enabled, checked controls are included.- Modern code uses
new FormData(form),new URLSearchParams(formData)andformData.getAll(). - Send with
$.post(form.action, $(form).serialize())orfetch(form.action, { method: "POST", body: ... }). - Validate with HTML attributes,
checkValidity(),reportValidity()andsetCustomValidity(), and always validate on the server too.
Exercise
Build a "Book a cricket net" form with name (required), phone (pattern for a 10-digit number starting 6 to 9), date and a "with coach" checkbox. On submit, prevent the reload, and if this.checkValidity() is false call this.reportValidity() and stop. Otherwise show the .serialize() string in a paragraph and the number of fields sent (from .serializeArray().length).
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Net booking</title>
</head>
<body>
<form id="booking" novalidate>
<label>Name <input name="name" required></label><br>
<label>Phone <input name="phone" pattern="[6-9][0-9]{9}" required></label><br>
<label>Date <input name="date" type="date" required></label><br>
<label><input type="checkbox" name="coach" value="yes"> With coach</label><br>
<button>Book</button>
</form>
<p id="out"></p>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
$("#booking").on("submit", function (event) {
event.preventDefault();
if (!this.checkValidity()) {
this.reportValidity();
return;
}
const fields = $(this).serializeArray();
$("#out").text($(this).serialize() + " (" + fields.length + " fields)");
});
</script>
</body>
</html>novalidate stops the browser from blocking the submit by itself, so your handler decides when to show the messages with reportValidity(); the unticked coach box is not sent, so the count is 3 or 4.
Quick Quiz
1. Which fields does .serialize() include?
It follows the same rules as a real form submission.
2. What is the modern equivalent of $(form).serialize()?
FormData collects the fields and URLSearchParams encodes them as a query string.
3. Why handle the form's submit event rather than the button's click?
Users often press Enter in a text field; only the submit event catches every way of sending the form.
4. Object.fromEntries(new FormData(form)) is used on a form with two ticked "subjects" checkboxes. What happens?
Use formData.getAll("subjects") for fields with several values.
Learn jQuery with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
