jQuery / Method / .submit() — Form submission events
Handle a form’s submission with $(form).on("submit", handler). To request submission through browser validation, use form.requestSubmit(). The old jQuery .submit() shorthand, a jQuery event trigger, and native form.submit() have different validation and event paths.
Binding versus requesting submission
The jQuery .submit() shorthand was deprecated in 3.3. With a handler it binds; with no arguments it triggers. Both remain callable in the tested full versions 3.7.1 and 4.0.0, but new code should use clearer explicit APIs. Deprecated does not automatically mean removed.
The submit event belongs to the form. Handling it there covers clicks, Enter, and scripted requests at one point. Checks attached only to a button click can miss other submission routes.
| Method | Validation and event | Purpose |
|---|---|---|
| .on("submit", handler) | Binds a handler; does not submit | Process submission events |
| Submit button / requestSubmit() | Constraints first, then submit if valid | Ordinary submission request |
| jQuery .trigger("submit") | Runs jQuery handlers, not the same constraint path | Deliberate event triggering |
| Native form.submit() | Bypasses constraints and submit event | Special intentional bypass |
Complete comparison example
Save UTF-8 as submit-demo.html and open it. Internet loads full jQuery 4.0.0; no server or build is needed. preventDefault stops every submission and only displays results. No external sending or storage occurs. Windows Edge with 4.0.0 and 3.7.1 tested these paths and submitting-button data.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Inspect form submit events</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 720px; margin: 20px; }
label { display: block; margin-top: 12px; }
input, select, button { font: inherit; max-width: 100%; margin: 5px 0; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<form id="chooser">
<label for="person">Name</label>
<input id="person" name="person" required>
<label for="fruit">Fruit</label>
<select id="fruit" name="fruit" required>
<option value="">Choose a fruit</option>
<option value="apple">Apple</option><option value="banana">Banana</option>
</select>
<button id="inside" type="submit" name="intent" value="inside">Inspect inside</button>
</form>
<button id="outside" type="submit" form="chooser" name="intent" value="outside">Inspect outside</button>
<button id="request" type="button">requestSubmit(inside)</button>
<button id="trigger" type="button">jQuery trigger submit</button>
<button id="restore" type="button">Reset</button>
<label><input id="automatic" type="checkbox">Request submission when fruit changes</label>
<pre id="result" aria-live="polite">events=0
No submission inspected.</pre>
<script>
jQuery(function ($) {
const form = document.querySelector("#chooser");
let events = 0;
$(form).on("submit", function (event) {
event.preventDefault(); events++;
if (!form.reportValidity()) {
$("#result").text("events=" + events + "\nInvalid data; not inspected."); return;
}
const submitter = event.originalEvent ? event.originalEvent.submitter : null;
const data = submitter ? new FormData(form, submitter) : new FormData(form);
$("#result").text("events=" + events + "\nsubmitter=" + (submitter ? submitter.id : "(none)") +
"\nvalues=" + JSON.stringify(Object.fromEntries(data)));
});
$("#request").on("click", function () { form.requestSubmit(document.querySelector("#inside")); });
$("#trigger").on("click", function () { $(form).trigger("submit"); });
$("#fruit").on("change", function () {
if (document.querySelector("#automatic").checked) form.requestSubmit();
});
$("#restore").on("click", function () {
form.reset(); document.querySelector("#automatic").checked = false; events = 0;
$("#result").text("events=0\nNo submission inspected.");
});
});
</script>
</body>
</html>
Initial output. events counts handler entries, not successful server writes.
events=0
No submission inspected.
- With empty fields, try Inspect inside, Inspect outside, and requestSubmit(inside). required blocks them first, leaving events=0.
- jQuery trigger submit enters the handler and reaches events=1, but reportValidity produces Invalid data; not inspected.
- Reset, enter JB and Apple, then Inspect inside. events=1, submitter=inside, and person/fruit/intent values appear.
- Inspect outside gives submitter=outside and intent=outside. Its form="chooser" associates the external button.
- requestSubmit(inside) specifies that button. Enter in Name also uses the first submit button inside in this example.
- With valid input, jQuery trigger submit has submitter=(none) and no button intent.
- Enable Request submission when fruit changes and select Banana. requestSubmit() with no button has submitter=(none).
- Reset restores values, automatic-request checkbox, and counter.
event.originalEvent.submitter reads the native SubmitEvent button. Synthetic jQuery events may have no originalEvent, so the handler branches. FormData(form, submitter) includes that button’s name/value. Object.fromEntries retains only the last value for duplicate names; this single-value display is not an array-collection pattern.
External controls, automatic requests, and prevention
A real button type="submit" with a form attribute gives external controls normal keyboard and submission behavior. Being outside the form does not itself bypass required; the API used determines that behavior.
requestSubmit() performs constraint validation and dispatches submit when valid. An explicit submitter must be a submit button associated with that form. The example covers calls with and without one.
Immediate submission on select change can surprise keyboard users while choosing. This example requires opting in and prevents navigation. Decide whether a filter should apply immediately or require confirmation. A .val() setter alone does not emit change.
preventDefault stops the default submission. If waiting for asynchronous work, prevent it synchronously in the handler; calling it after await cannot undo a submission already underway. This example has no asynchronous transport. A real implementation needs in-progress state, duplicate-request handling, recovery, and server validation.
Legacy shorthand and native method
Run this small legacy probe after initialization. Its detached form prevents the default action, so there is no server request.
const $probe = $("<form>");
let calls = 0;
$probe.submit(function (event) {
event.preventDefault();
calls++;
});
$probe.submit();
console.log("legacy calls=" + calls);
Console output; distinguish calls with a handler from calls without arguments when reading old code.
legacy calls=1
.trigger("submit") runs handlers and can continue to a native method when the default is not prevented. It is not a complete simulation of clicking a button and browser constraints. The example checks reportValidity even for a synthetic event.
HTMLFormElement.submit() bypasses constraints and does not call submit handlers. A separate test submitted an empty required field to an iframe and intercepted its request locally, confirming empty data and zero events. It did not test storage by a real receiving server.
For form.submit is not a function, inspect a control named or identified as submit masking the method. Avoid collisions with reset too, and distinguish a jQuery collection from a DOM form. requestSubmit is a DOM method; retrieve the form element with [0] when starting from jQuery.
Real server submission needs a suitable action, method, and receiver; adapt this demonstration’s unconditional prevention and output. A Valid display does not prove storage, and browser required is not a substitute for server checks.




