jQuery / Selector / :checked — Selecionar caixas e botões de opção marcados

jQuery :checked corresponde a caixas e rádios marcados, além de opções selecionadas. Restrinja tipo e escopo, como input[type="checkbox"]:checked. Use map para vários valores e leia rádios pelo elemento marcado do grupo name.

Estado marcado e valor são diferentes

A referência :checked inclui option, portanto o total do formulário não precisa ser uma contagem de caixas. O exemplo separa channels e plan; Priority acrescenta uma opção ao total.

.val() lê o value configurado mesmo sem marcação: SMS desmarcado retorna sms. .prop("checked") consulta um elemento, .is(":checked") qualquer correspondência e .filter(":checked") a coleção correspondente. Um getter de propriedade em vários lê só o primeiro.

Rádios com mesmo name no mesmo formulário são exclusivos. Restrinja formulário e nome. Sem escolha, a coleção marcada fica vazia e .val() pode ser undefined.

Exemplo completo de comparação

Salve e abra checked-demo.html em UTF-8. A internet carrega jQuery completo 4.0.0, sem servidor ou compilação. Windows Edge com 4.0.0 e 3.7.1 verificou teclado, arrays, desabilitados, change dinâmico e Reset. Nada é enviado ao servidor.

<!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>

Três channels estão marcados no início, mas só Email pode ser enviado. globalChecked vale cinco com rádio e opção.

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
  1. Marque SMS com clique ou Espaço: submittedChannels vira ["email","sms"] sob o mesmo nome repetido.
  2. Pro desmarca Basic e produz radio=pro, também por setas via change.
  3. Reset e Choose SMS and Pro mantém só SMS entre ativos, com Archive/Legacy desabilitados; radio=pro, changes=2.
  4. checkedAttributes conserva os padrões email/archive/legacy.
  5. Clear enabled channels esvazia enabledBoxes e submittedChannels mantendo os desabilitados.
  6. Reset restaura caixas, rádio, Priority e contador.

checkedBoxes contém valores marcados, enabledBoxes os filtrados por :enabled e submittedChannels o FormData.getAll real. changes conta manipuladores, vários se vários controles emitem; não é quantidade de cliques.

Atributo, propriedade e atualização

[checked] consulta atributo HTML; a propriedade DOM checked e :checked descrevem o presente. O padrão se relaciona a defaultChecked e pode permanecer após desmarcar. Não use [checked] nem a verdade de .attr("checked") para o estado atual.

.prop("checked", true ou false) muda sem emitir change. O exemplo dispara explicitamente e renderiza no início. Se o relatório não mudar após atribuição programada, confira eventos e render.

change é delegado do formulário persistente para input/select. Controles posteriores podem propagar ao manipulador, e render busca caixas novamente. Uma coleção :checked armazenada não atualiza automaticamente seus membros.

Reset usa form.reset() e render. O id restore evita ocultar o método. Mudar atributos padrão ou valores iniciais de novos controles muda também o resultado da restauração.

Desabilitados e múltiplos valores enviados

Uma caixa disabled, inclusive dentro de fieldset desabilitado, pode continuar marcada. :checked não prova que possa ser enviada. :enabled considera a herança; FormData omite Archive/Legacy. Conferir só a ausência de [disabled] perde esses descendentes.

Caixas e rádios desmarcados normalmente faltam nos dados, sem string false automática. Sem value, uma caixa vale on. Use identificadores significativos e defina no servidor as regras para ausência.

FormData.getAll() preserva nomes repetidos. Object.fromEntries com uma chave pode perder valores. Confira convenções de arrays do framework e valide valores permitidos e combinações no servidor.

:checked também funciona em querySelectorAll nativo. Para opções, restrinja a option:checked ou jQuery :selected. Ao decorar, mantenha estado real do input e associação label para combinar cor e seleção.