jQuery / Selector / :checked — Select checked checkboxes and radio buttons
jQuery :checked matches checked checkboxes and radios, plus selected options. Restrict type and scope, such as input[type="checkbox"]:checked, when reading checkbox values. Map multiple choices into an array; read radio values from the checked element in its name group.
Checked state is not value
The :checked reference includes options, so a form-wide count need not be a checkbox count. This example separates channels checkboxes and plan radios; Priority contributes a selected option to the broad count.
.val() on a checkbox reads its configured value regardless of checked state: unchecked SMS still has value sms. Use .prop("checked") for one element, .is(":checked") for any match in a set, and .filter(":checked") for the checked collection. A property getter on several elements reads only the first.
Radios sharing a name in the same form form an exclusive group. Scope by form and name. If none is checked, the checked collection is empty and its .val() can be undefined.
Complete checkbox, radio, and form comparison
Save UTF-8 as checked-demo.html and open it. Internet loads full jQuery 4.0.0 without a server or build. Windows Edge with 4.0.0 and 3.7.1 tested keyboard input, arrays, disabled controls, dynamic change, and reset. Output stays on screen with no server submission.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checked controls and form data</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
fieldset { margin: 12px 0; }
label { display: block; }
button, select { font: inherit; max-width: 100%; margin: 4px; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<form id="preferences">
<fieldset id="channels"><legend>Channels</legend>
<label><input id="email" type="checkbox" name="channels" value="email" checked>Email</label>
<label><input id="sms" type="checkbox" name="channels" value="sms">SMS</label>
<label><input type="checkbox" name="channels" value="archive" checked disabled>Archive (disabled)</label>
<fieldset disabled><legend>Unavailable</legend>
<label><input type="checkbox" name="channels" value="legacy" checked>Legacy</label>
</fieldset>
</fieldset>
<fieldset><legend>Plan</legend>
<label><input id="basic" type="radio" name="plan" value="basic" checked>Basic</label>
<label><input id="pro" type="radio" name="plan" value="pro">Pro</label>
</fieldset>
<label for="priority">Priority</label>
<select id="priority" name="priority"><option value="normal">Normal</option><option value="high">High</option></select>
<button type="button" id="choose">Choose SMS and Pro</button>
<button type="button" id="clear">Clear enabled channels</button>
<button type="button" id="restore">Reset</button>
</form>
<pre id="result" aria-live="polite"></pre>
<script>
jQuery(function ($) {
const $form = $("#preferences"), form = $form[0];
let changes = 0;
function boxes() { return $form.find('input[type="checkbox"][name="channels"]'); }
function values($elements) { return $elements.map(function () { return this.value; }).get(); }
function render() {
const $checked = boxes().filter(":checked"), data = new FormData(form);
$("#result").text("checkedBoxes=" + JSON.stringify(values($checked)) +
"\nenabledBoxes=" + JSON.stringify(values($checked.filter(":enabled"))) +
"\nradio=" + ($form.find('input[name="plan"]:checked').val() || "(none)") +
"\ncheckedAttributes=" + JSON.stringify(values(boxes().filter("[checked]"))) +
"\nsubmittedChannels=" + JSON.stringify(data.getAll("channels")) +
"\nform=" + new URLSearchParams(data).toString() +
"\nglobalChecked=" + $form.find(":checked").length + "\nchanges=" + changes);
}
$form.on("change", "input, select", function () { changes++; render(); });
$("#choose").on("click", function () {
boxes().filter(":enabled").prop("checked", false);
$("#sms").prop("checked", true).trigger("change");
$("#pro").prop("checked", true).trigger("change");
});
$("#clear").on("click", function () { boxes().filter(":enabled").prop("checked", false).trigger("change"); });
$("#restore").on("click", function () { form.reset(); changes = 0; render(); });
render();
});
</script>
</body>
</html>
Initially three channels are checked but only Email is eligible for submission. globalChecked is five because it includes the radio and selected option.
checkedBoxes=["email","archive","legacy"]
enabledBoxes=["email"]
radio=basic
checkedAttributes=["email","archive","legacy"]
submittedChannels=["email"]
form=channels=email&plan=basic&priority=normal
globalChecked=5
changes=0
- Click SMS or focus it and press Space. submittedChannels becomes ["email","sms"] and both appear under repeated channels names.
- Choose Pro, including with arrow keys. Basic clears and radio=pro updates through change.
- Reset, then Choose SMS and Pro. Only SMS remains checked among enabled channels; disabled Archive and Legacy stay checked. radio is pro and changes is two.
- checkedAttributes still lists initial email/archive/legacy because defaults differ from current state.
- Clear enabled channels empties enabledBoxes and submittedChannels while preserving disabled checks.
- Reset restores initial checks, radio, Priority, and counter.
checkedBoxes lists current checked values, enabledBoxes filters them with :enabled, and submittedChannels uses real FormData.getAll. changes counts handler executions: clearing several enabled controls emits one event per control. It is not a user-click counter.
Attributes, properties, and refresh
[checked] tests an HTML attribute; the DOM checked property and :checked describe current checks. The default is associated with defaultChecked, so unchecking need not remove the attribute. Do not infer current state from [checked] or .attr("checked") truthiness.
.prop("checked", true or false) changes current state without automatically emitting change. The example triggers change to refresh output and renders once initially. If a scripted assignment leaves the report unchanged, inspect the event/render path.
Change is delegated from the persistent form to inputs and selects. Later controls can bubble into the same handler, and render queries checkbox elements again each time. A previously saved :checked collection does not automatically update its membership as people interact.
Reset uses form.reset() followed by render. Its button id restore avoids masking the reset method. Changing default attributes or adding controls with different defaults also changes what reset restores.
Disabled controls and repeated submitted values
A disabled checkbox, including one inside disabled fieldset, can stay checked. :checked alone does not establish submission eligibility. :enabled accounts for inherited disabling; FormData omits Archive and Legacy. Testing only the absence of a disabled attribute misses fieldset-disabled descendants.
Unchecked checkboxes and radios are normally absent from form data; they do not automatically send a false string. A checkbox without value defaults to on, so provide meaningful identifiers and define missing-value rules for the server.
Preserve repeated names with FormData.getAll(). Converting to a single object key with Object.fromEntries can discard values. Check the server framework’s array-field naming rules separately and validate allowed identifiers and combinations on the server.
:checked also works in native querySelectorAll. For options only, restrict to option:checked or jQuery :selected. When styling selection, keep actual input state and label association intact so visual color and real selection do not diverge.




