67

I have been asked to disable the "ticking" of a checkbox. I am not being asked to disable the checkbox, but to simply disable the "ticking".

In other words, a user will think that a checkbox is tickable, but it is not. Instead, clicking on the checkbox will cause a modal dialog to appear, giving the user more options to turn on or off the feature that the checkbox represents. If the options chosen in the dialog cause the feature to be turned on, then the checkbox will be ticked.

Now, the real problem is that for a split second, you can still see that the checkbox is being ticked.

I have tried an approach like this:

<input type='checkbox' onclick='return false' onkeydown='return false' />

$('input[type="checkbox"]').click(function(event) {
    event.preventDefault();
    alert('Break');
});

If you run this, the alert will appear, showing that the tick is visible (the alert is just there to demonstrate that it still does get ticked, in production, the alert is not there). On some users with slower machines and/or in browsers with slow renderers/javascript, users can see a very faint flicker (the flicker sometimes lasts for half a second, which is noticeable).

A tester in my team has flagged this as a defect and I am supposed to fix it. I'm not sure what else I can try to prevent the tick in the checkbox from flickering!

17 Answers 17

28

From my point of view it is as simple as:

$(this).prop('checked', !$(this).prop('checked'));

Works both for checked and unchecked boxes

Sign up to request clarification or add additional context in comments.

1 Comment

In vanilla JS: this.checked = !this.checked
24

Try

event.stopPropagation();

http://jsfiddle.net/DrKfE/3/

3 Comments

Unfortunately, this does not appear to completely stop the checkbox from ticking. Using my sample code above, you will see that when the alert appears, the checkbox is still ticked. At least, it is in Chrome.
Actually, ISWYDT, the "return false" is before the alert. Unfortunately, I can't use this approach as I need a modal dialog to pop-up after the checkbox is ticked. I think stopPropagation() is preventing the handler which does this (when the checkbox is clicked) from firing.
Actually, it is the "return false" which is preventing the modal dialog handler from firing, not stopPropagation(). I tried this version of your code and the checkbox is still ticked: jsfiddle.net/737hX/1
20

Best solution I've come up with:

$('input[type="checkbox"]').click(function(event) {
    var $checkbox = $(this);

    // Ensures this code runs AFTER the browser handles click however it wants.
    setTimeout(function() {
      $checkbox.removeAttr('checked');
    }, 0);

    event.preventDefault();
    event.stopPropagation();
});

2 Comments

It wouldn't be the first time a setTimeout() function was used to achieve this functionality!
Works for me, I had to handle onclick event and send an ajax request, thus only change the checked state upon succesfull ajax callback.
10

This effect can't be suppressed I fear. As soon as you click on the checkbox, the state (and rendering) is changed. Then the event handlers will be called. If you do a event.preventDefault(), the checkbox will be reset after all the handlers are executed. If your handler has a long execution time (easily testable with a modal alert()) and/or the rendering engine repaints before reseting, the box will flicker.

$('input[type="checkbox"]').click(function(event) {
    this.checked = false; // reset first
    event.preventDefault();
    // event.stopPropagation() like in Zoltan's answer would also spare some
    // handler execution time, but is no more needed here

    // then do the heavy processing:
    alert('Break');
});

This solution will reduce the flickering to a minimum, but can't hinder it really. See Thr4wn's and RobG's answer for how to simulate a checkbox. I would prefer the following:

<button id="settings" title="open extended settings">
    <img src="default_checkbox.png" />
</button>
document.getElementById("settings").addEventListener("click", function(e) {
    var img = this.getElementsByTagName("img")[0]);
    openExtendedSettingsDialog(function callbackTick() {
        img.src = "checked_checkbox.png";
    }, function callbackUntick() {
        img.src = "unchecked_checkbox.png";
    });
}, false);

Comments

10

It is very important to use return false at the end.

Something like this:

$("#checkbox").click((e) => {
  e.stopPropagation();
  return false;
});

1 Comment

This is the only correct answer
9

Isn't is simpler ? :

<input type="checkbox" onchange="this.checked = !this.checked">

1 Comment

Even that this is not answering the question, it is a compact solution for preventing checkbox changes on click. Thanks.
8

TL:DR;

HTML api's execute before JavaScript. So you must use JavaScript to undo HTML's changes.

event.target.checked = false

WHAT is the problem?

Strictly speaking: we cannot "stop" the checkbox from being ticked. Why not? Because "being ticked" exactly means that the DOM's, HTML <input> element has a checked property value of true or false, which is immediately assigned by the HTML api

console.log(event.target.checked) // will be opposite of the previous value

So it's worth explicitly mentioning this HTML api is called before scripts. Which is intuitive and should make sense, because all JavaScript files are themselves the assignment of a <script> element's attribute src, and the ancestral relationship in the DOM tree, between your <input> in question, and the <script> element running your JavaScript, is extremely important to consider.

HOW to get our solution

The HTML assigned value has not yet been painted before we have a chance to intercept the control flow (via JS file like jQuery), so we simply re-assign the checked property to a boolean value we want: false (in your case).

So in conclusion, we CAN, in-effect, "stop" the checkbox from being checked, by simply ensuring that the checked property is false on the next render and thus, won't see any changes.

1 Comment

Is form submission part of HTML API? if yes, why we can stop it by JS?
3

Why not simply add a class in your CSS that sets pointer-events: none;?

Something like:

<style>
    input.lockedCbx { pointer-events: none; }
</style>
...
<input type="checkbox" class="lockedCbx" tabindex=-1 />
...

You need the tabindex=-1 to prevent users from tabbing into the checkbox and pressing a space bar to toggle.

Now in theory you could avoid the class and use the tabindex=-1 to control the disabling as in:

<script>
    input[type="checkbox"][tabindex="-1"] { pointer-events: none; }
</script>

Comments

2

With CSS, you can change the image of the checkbox. See http://ryanfait.com/resources/custom-checkboxes-and-radio-buttons/ and also CSS Styling Checkboxes .

I would disable the checkbox, but replace it with an image of a working checkbox. That way the checkbox doesn't look disabled, but won't be clickable.

Comments

2

Sounds to me like you are using the wrong interface element, a more suitable one would be a button that is disabled by default, but enabled when that option is available. The image displayed can be whatever you want.

<button disabled onclick="doSomething();">Some option</button>

When users have selected that feature, enable the button. The image on the button can be modified by CSS depending on whether it's enabled or not, or by the enable/disable function.

e.g.

<script type="text/javascript">

function setOption(el) {
  var idMap = {option1:'b0', option2: 'b1'};
  document.getElementById(idMap[el.value]).disabled = !el.checked; 
}

</script>

<div><p>Select options</p>
  <input type="checkbox" onclick="setOption(this);" value="option1"> Option 1
  <br>
  <input type="checkbox" onclick="setOption(this);" value="option2"> Option 2
  <br>
</div>
<div>
  <button id="b0" onclick="alert('Select…');" disabled>Option 1 settings</button>
  <button id="b1" onclick="alert('Select…');" disabled>Option 2 settings</button>
</div>

2 Comments

Good thought. Yet, I wouldn't say the button to open the dialog should be disabled - it just should replace the checkbox. The state should be indicated by the button's labelling.
Using disabled most closely does what the OP wants. It also avoids hiding and showing different sized elements (checkbox vs button), which leads to layout complications. I'm nearly always in favour of the simplest solution that does the job.
2

Wrap the checkbox with another element that somehow blocks pointer events (probably via CSS). Then, handle the wrapper's click event instead of the checkbox directly. This can be done a number of ways but here's a relatively simple example implementation:

$('input[type="checkbox"').parent('.disabled').click( function() {
    
    // Add in whatever functionality you need here
    
    alert('Break');
    
});
/* Insert an invisible element that covers the checkbox */
.disabled {
    position: relative;
}
.disabled::after {
    content: "";
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<!-- Only wrapped checkboxes are "disabled" -->
<input type="checkbox" />
<span class="disabled"><input type="checkbox" /></span>
<input type="checkbox" />
<span class="disabled"><input type="checkbox" /></span>
<span class="disabled"><input type="checkbox" /></span>
<input type="checkbox" />

Note: You could also add the wrapper elements programmatically, if you would like.

Comments

1
$('#term-input').on('change click',function (e){
   e.preventDefault();
})

works for me

1 Comment

Add more explanation
0

The Event.preventDefault method should work for change, keydown, and mousedown events, but doesn't in my testing.

My solution to this problem in a Mozilla Firefox 53.0 extension was to toggle an HTML class that enabled/disabled the CSS declaration pointer-events: none being applied to the checkbox. This addresses the cursor-based case, but not the key-based case. See https://www.w3.org/TR/SVG2/interact.html#PointerEventsProp.

I addressed the key-based case by adding/removing an HTML tabindex="-1" attribute. See https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex.

Note that disabling pointer-events will disable your ability to trigger CSS cursors on hover (e.g., cursor: not-allowed). My checkbox was already wrapped in a span element, so I added an HTML class to that span element which I then retargeted my CSS cursor declaration onto.

Also note that adding a tabindex="-1" attribute will not remove focus from the checkbox, so one will need to explicitly defocus it by using the HTMLElement.blur() method or by focusing another element to prevent key-based input if the checkbox is the active element at the time the attribute is added. Whether or not the checkbox is the focused element can be tested with my_checkbox.isEqualNode(document.activeElement).

Comments

0

Simply revert the value back

$('input[type="checkbox"]').on('change', function(e) {
    if (new Date().getDate() === 13) {
        $(this).prop('checked', !$(this).prop('checked'));
        e.preventDefault();
        return false;
     }
     // some code here
});

Comments

0

Add this to click event in js file

event.stopPropagation();                  

Comments

0

In my case I needed the checkbox to get the checked state only via an Input property and not via a mouse click. In an Angular app this did the trick:

<input [checked]="someCondition" (click)="$event.preventDefault()">

Comments

0

The "checked value change" event is not cancelable. So the idea I did is simple. Wrap the checkbox with <label></label> tag and make the checkbox as not clickable element. Now you can control the checkbox value changes with "click" event from <label>.

<label (click)="onLabelClick($event)">
  <input type="checkbox" style="pointer-events:none"/>
</label>
onLabelClick(event){
  if(someCondition){ event.preventDefault() }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.