Chrome and Edge treating a checkbox set to "indeterminate" differently when checked

Viewed 1305

Note: I'm using jQuery to access the DOM element but plain JavaScript to assign the event to it, so I doubt jQuery has anything to do with it

Check this jsFiddle.

$(document).ready(function() {
  $('input')[0].indeterminate = true;
  $('input')[0].addEventListener("click", function(event) {
    console.log(event.target.checked)
    alert("Check is: " + event.target.checked);
  })
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" checked>

If you open it on Chrome and click on the checkbox, the alert message says "Check is: false" whereas if you open it on Microsoft Edge and click on the checkbox, the message says "Check is: true", meaning that the state of the check property changes with the browser.

I tried setting the checked property along with the indeterminate property to see if I enforced that it would treat it the same way, but the results are the same

$(document).ready(function() {
  $('input')[0].indeterminate = true;
  $('input')[0].checked = false;

  $('input')[0].addEventListener("click", function(event) {
    console.log(event.target.checked)
    alert("Check is: " + event.target.checked);
  })
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" checked>

Is this a bug on Edge or Chrome or is there a way to have a congruent behavior across all browsers?

1 Answers

This behavior is related to the indeterminate property. Please refer to Racil Hilan 's reply on this thread.

Checkbox inputs can only have two states: checked or unchecked. The indeterminate state is visual only and it masks the real state of the checkbox.

The first time you click on a checkbox that has its indeterminate set to "true" will simply change it to false and the checkbox will show its real state. For that reason, the change from "indeterminate" to either "checked" or "unchecked" is not a change in the real state and it does not trigger the "onchange" event.

Although IE implementation is the correct one technically, the implementation of the other browsers is the more practical one. For most applications, the visual "indeterminate" state needs to be considered as a real state just like the "checked" and "unchecked" which means that the change from any of those 3 states to another one should trigger the onchange event.

You could add a change event to verify it. In IE and Edge, the first time you click on a checkbox, it will not trigger the change event, just reveal the real state of the checkbox. But, in Chrome, it will trigger the change event and change the real state to the other real state. code as below:

<body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('input')[0].indeterminate = true;
            //$('input')[0].checked = false;
            $('input')[0].addEventListener("click", function (event) {
                console.log(event.target.checked)
                alert("Check is: " + event.target.checked);
            });

            $('input')[0].addEventListener("change", function (event) {
                console.log(event.target.checked)
                alert("change event Check is: " + event.target.checked);
            })            
        });
    </script>
    <input type="checkbox" checked>
</body>

Is this a bug on Edge or Chrome or is there a way to have a congruent behavior across all browsers?

If you want to have a congruent behavior across all browsers, you could try to set the indeterminate to false or remove this property.

Also, you could refer to the following code to use one-time click event:

<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript">
        $(function () {
            var checkbox = document.getElementById("cb");
            checkbox.indeterminate = true;
            $('#cb').one('click', function (e) {
                if (!this.checked) {
                    this.checked = true;
                    var evt = document.createEvent("HTMLEvents");
                    evt.initEvent("change", false, true);
                    this.dispatchEvent(evt);
                }
                alert(e.target.checked);
            }).change(function (e) {
                console.log(e);
                alert(e.target.checked)
            });
        });
    </script>
</head>
<body>
    <label for="cb"> 
        <input id="cb" type="checkbox" checked />click me
    </label>
</body>
Related