[forms] Required attribute on multiple checkboxes with the same name?

I have a list of checkboxes with the same name attribute, and I need to validate that at least one of them has been selected.

But when I use the html5 attribute "required" on all of them, the browser (chrome & ff) doesn't allow me to submit the form unless all of them are checked.

sample code:

<label for="a-0">a-0</label>
<input type="checkbox" name="q-8" id="a-0" required />
<label for="a-1">a-1</label>
<input type="checkbox" name="q-8" id="a-1" required />
<label for="a-2">a-2</label>
<input type="checkbox" name="q-8" id="a-2" required />

When using the same with radio inputs, the form works as expected (if one of the options is selected the form validates)

According to Joe Hopfgartner (who claims to quote the html5 specs), the supposed behaviour is:

For checkboxes, the required attribute shall only be satisfied when one or more of the checkboxes with that name in that form are checked.

For radio buttons, the required attribute shall only be satisfied when exactly one of the radio buttons in that radio group is checked.

am i doing something wrong, or is this a browser bug (on both chrome & ff) ??

This question is related to forms html

The answer is


You can make it with jQuery a less lines:

$(function(){

    var requiredCheckboxes = $(':checkbox[required]');

    requiredCheckboxes.change(function(){

        if(requiredCheckboxes.is(':checked')) {
            requiredCheckboxes.removeAttr('required');
        }

        else {
            requiredCheckboxes.attr('required', 'required');
        }
    });

});

With $(':checkbox[required]') you select all checkboxes with the attribute required, then, with the .change method applied to this group of checkboxes, you can execute the function you want when any item of this group changes. In this case, if any of the checkboxes is checked, I remove the required attribute for all of the checkboxes that are part of the selected group.

I hope this helps.

Farewell.


To provide another approach similar to the answer by @IvanCollantes. It works by additionally filtering the required checkboxes by name. I also simplified the code a bit and checks for a default checked checkbox.

_x000D_
_x000D_
jQuery(function($) {_x000D_
  var requiredCheckboxes = $(':checkbox[required]');_x000D_
  requiredCheckboxes.on('change', function(e) {_x000D_
    var checkboxGroup = requiredCheckboxes.filter('[name="' + $(this).attr('name') + '"]');_x000D_
    var isChecked = checkboxGroup.is(':checked');_x000D_
    checkboxGroup.prop('required', !isChecked);_x000D_
  });_x000D_
  requiredCheckboxes.trigger('change');_x000D_
});
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>_x000D_
<form target="_blank">_x000D_
  <p>_x000D_
    At least one checkbox from each group is required..._x000D_
  </p>_x000D_
  <fieldset>_x000D_
    <legend>Checkboxes Group test</legend>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test[]" value="1" checked="checked" required="required">test-1_x000D_
    </label>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test[]" value="2" required="required">test-2_x000D_
    </label>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test[]" value="3" required="required">test-3_x000D_
    </label>_x000D_
  </fieldset>_x000D_
  <br>_x000D_
  <fieldset>_x000D_
    <legend>Checkboxes Group test2</legend>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test2[]" value="1" required="required">test2-1_x000D_
    </label>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test2[]" value="2" required="required">test2-2_x000D_
    </label>_x000D_
    <label>_x000D_
      <input type="checkbox" name="test2[]" value="3" required="required">test2-3_x000D_
    </label>_x000D_
  </fieldset>_x000D_
  <hr>_x000D_
  <button type="submit" value="submit">Submit</button>_x000D_
</form>
_x000D_
_x000D_
_x000D_


Here is improvement for icova's answer. It also groups inputs by name.

$(function(){
  var allRequiredCheckboxes = $(':checkbox[required]');
  var checkboxNames = [];

  for (var i = 0; i < allRequiredCheckboxes.length; ++i){
    var name = allRequiredCheckboxes[i].name;
    checkboxNames.push(name);
  }

  checkboxNames = checkboxNames.reduce(function(p, c) {
    if (p.indexOf(c) < 0) p.push(c);
    return p;
  }, []);

  for (var i in checkboxNames){
    !function(){
      var name = checkboxNames[i];
      var checkboxes = $('input[name="' + name + '"]');
      checkboxes.change(function(){
        if(checkboxes.is(':checked')) {
          checkboxes.removeAttr('required');
        } else {
          checkboxes.attr('required', 'required');
        }
      });
    }();
  }

});

i had the same problem, my solution was apply the required attribute to all elements

<input type="checkbox" name="checkin_days[]" required="required" value="0" /><span class="w">S</span>
<input type="checkbox" name="checkin_days[]" required="required" value="1" /><span class="w">M</span>
<input type="checkbox" name="checkin_days[]" required="required" value="2" /><span class="w">T</span>
<input type="checkbox" name="checkin_days[]" required="required" value="3" /><span class="w">W</span>
<input type="checkbox" name="checkin_days[]" required="required" value="4" /><span class="w">T</span>
<input type="checkbox" name="checkin_days[]" required="required" value="5" /><span class="w">F</span>
<input type="checkbox" name="checkin_days[]" required="required" value="6" /><span class="w">S</span>

when the user check one of the elements i remove the required attribute from all elements:

var $checkedCheckboxes = $('#recurrent_checkin :checkbox[name="checkin_days[]"]:checked'),
    $checkboxes = $('#recurrent_checkin :checkbox[name="checkin_days[]"]');

$checkboxes.click(function() {

if($checkedCheckboxes.length) {
        $checkboxes.removeAttr('required');
    } else {
        $checkboxes.attr('required', 'required');
    }

 });

var verifyPaymentType = function () {
   //coloque os checkbox dentro de uma div com a class checkbox
  var inputs =  window.jQuery('.checkbox').find('input');
  var first = inputs.first()[0];

  inputs.on('change', function () {
    this.setCustomValidity('');
  });

  first.setCustomValidity( window.jQuery('.checkbox').find('input:checked').length === 0 ? 'Choose one' : '');
}

window.jQuery('#submit').click(verifyPaymentType);

}

A little jQuery fix:

$(function(){
    var chbxs = $(':checkbox[required]');
    var namedChbxs = {};
    chbxs.each(function(){
        var name = $(this).attr('name');
        namedChbxs[name] = (namedChbxs[name] || $()).add(this);
    });
    chbxs.change(function(){
        var name = $(this).attr('name');
        var cbx = namedChbxs[name];
        if(cbx.filter(':checked').length>0){
            cbx.removeAttr('required');
        }else{
            cbx.attr('required','required');
        }
    });
});

Building on icova's answer, here's the code so you can use a custom HTML5 validation message:

$(function() {
    var requiredCheckboxes = $(':checkbox[required]');
    requiredCheckboxes.change(function() {
        if (requiredCheckboxes.is(':checked')) {requiredCheckboxes.removeAttr('required');}
        else {requiredCheckboxes.attr('required', 'required');}
    });
    $("input").each(function() {
        $(this).on('invalid', function(e) {
            e.target.setCustomValidity('');
            if (!e.target.validity.valid) {
                e.target.setCustomValidity('Please, select at least one of these options');
            }
        }).on('input, click', function(e) {e.target.setCustomValidity('');});
    });
});