Unselecting Radio Buttons with jQuery

I got a weird request from one of my internal customers today. In one of our applications he wanted to be able to "uncheck" radio buttons.

We all know that if you have a group of radio buttons, like this, that once you select one option, you cannot unselect an option, you can only change from one option to another.


    <input type="radio" name="radio_group" />radio a<br />
    <input type="radio" name="radio_group" />radio b<br />
    <input type="radio" name="radio_group" />radio c<br />
Well, my customer wanted to be able to click on a checked radio button and "uncheck" it. At first, I said "No way, that's not the way that web applications work!". Then I thought about it and how I would do it in jQuery and I got inspired to try it and see what would happen. It would not be true for me to say that there have not been a few times when I would have liked this feature.

Here is what I came up with. UPDATE: The code below was provided in a comment from Jinxdone. It is much more elegant than my original code, so I am updating the entry to avoid having anyone use my code if they do not bother with the comments. Thanks Jinxdone!


<script type="text/javascript">
            $(function(){
                        var allRadios = $('input[type=radio]')
                        var radioChecked;
                        
                        var setCurrent =
                                        function(e) {
                                            var obj = e.target;
                             
                                            radioChecked = $(obj).attr('checked');
                                     }
                                                
                        var setCheck =
                                    function(e) {
                                        
                                        if (e.type == 'keypress' && e.charCode != 32) {
                                            return false;
                                        }
                                        
                                        var obj = e.target;
                                        
                             if (radioChecked) {
                             $(obj).attr('checked', false);
                             } else {
                             $(obj).attr('checked', true);
                             }
                                 }    
                                                 
                        $.each(allRadios, function(i, val){        
                             var label = $('label[for=' + $(this).attr("id") + ']');
                            
                         $(this).bind('mousedown keydown', function(e){
                                setCurrent(e);
                            });
                            
                            label.bind('mousedown keydown', function(e){
                                e.target = $('#' + $(this).attr("for"));
                                setCurrent(e);
                            });
                        
                         $(this).bind('click', function(e){
                                setCheck(e);    
                            });
                        
                        });
            });
</script>

So this is somewhat rudimentary quite elegant. , but it works. It has a few issues if you have JavaScript business logic that unchecks some of your radio buttons, because the click event doesn't happen then so the "checked" class does not get removed even though the radio button may have gotten unchecked. You would need to figure this out in your business logic or figure out a way to listen for that to happen and handle it. This solution also does not have the previous issues that mine had with other logic disabling, enabling and clearing other radio buttons.

UPDATE 7/8/2009: Thanks to comments from Tim and Jubal, I have added support for label element clicking and for keyboard input support.

Try it out here:

Group 1


Group 2

Comments
Todd Rafferty's Gravatar This isn't working for me in FF3.5b4 or IE8.
# Posted By Todd Rafferty | 6/9/09 3:29 PM
Jason Dean's Gravatar @Todd, interesting. I did not try it outside of FF3 and IE7. Maybe I will. Maybe :)
# Posted By Jason Dean | 6/9/09 3:30 PM
Todd Rafferty's Gravatar Well, I just thought I'd throw monkey-wrenches at you.
# Posted By Todd Rafferty | 6/9/09 3:32 PM
Jason Dean's Gravatar @Todd, were you trying my sample or did you actually take the code and make your own page and try it. I just realized that in my sample I accidentally left a console.log() statement in there, so it would fail in IE and possibly in a FF install that did not have FireBug.
# Posted By Jason Dean | 6/9/09 3:33 PM
Jason Dean's Gravatar @Todd, Thanks for the Monkey Wrenches. If only I could sell them on craig's list. I'm hoping the sample works now for you
# Posted By Jason Dean | 6/9/09 3:36 PM
jinxdone's Gravatar Here is a cleaner example. Get the state of the checkbox when the mousedown even fires, and then toggle it after the click event has happened.

   var radioChecked;
   $('input[type=radio]').bind('mousedown', function() {
      radioChecked = $(this).attr('checked');
   });
   $('input[type=radio]').bind('click', function() {
      if (radioChecked) {
         $(this).attr('checked', false);
      } else {
         $(this).attr('checked', true);
      }
   });
# Posted By jinxdone | 6/11/09 8:04 AM
Jason Dean's Gravatar @jinxdone Hey, very nice! Good use of event firing ordered. I had, obviously, not thought of that or the fact that on the MouseDown event that the status of the button had not changed yet.

If you don't mind, I will update my post to reflect this more elegant solution (giving proper credit, of course).
# Posted By Jason Dean | 6/11/09 8:21 AM
Kevin Marino's Gravatar Just thought I'd add a use case. Government forms. I can tell you that where I work we have a use case that is specificially looks at the radio check boxes. we have a Yes/No/Not Applicable options and there are business rules related to other fields that are related to whether a radio is checked or unchecked.
# Posted By Kevin Marino | 6/25/09 5:44 AM
Jason Dean's Gravatar @Kevin,

Thanks for the input. I was just "arguing" the other day with some people about radio buttons and states. One argument, that I am not completely against, is that a radio group should never have an unchecked state. There should always be a default option that is checked. That way, instead of needing to uncheck it, you can simple check the default option.

In the case of the application I was working on, unchecking was easier than going back and adding default options to all of the radio groups.

I guess I don't really see a problem with doing it either way.
# Posted By Jason Dean | 6/25/09 9:42 AM
Jubal's Gravatar Thanks for this code snippet (cheers, jinxdome).

Minor nit: the code doesn't work for the label tag surrounding the radio input type. I can select the text within the label tags in order to select the radio button, but un-selecting requires clicking directly on the radio button, which isn't intuitive.
# Posted By Jubal | 7/7/09 9:38 AM
Jason Dean's Gravatar @Jubal,

That's a good point. I'm going to look into that and see if i can address it easily.
# Posted By Jason Dean | 7/7/09 10:13 AM
Tim's Gravatar Problem still remains if you use the keyboard to select the options
# Posted By Tim | 7/8/09 1:57 AM
Tim's Gravatar $('input[type=radio]').each(function() {
$("label[for='" + $(this).attr('id') + "']").bind("mousedown", function(){
radioChecked = $("#"+ $(this).attr("htmlFor")).attr('checked');
});
});

This will do the trick for clicking the label
# Posted By Tim | 7/8/09 5:21 AM
Jason Dean's Gravatar @Tim and @Jubal,

Thanks for your comments and for reinforcing the importance of proper accessibility. I have updated my code to now support the <label> tags and for keyboard input.
# Posted By Jason Dean | 7/8/09 9:29 AM
impressthenet.com's Gravatar Thanks for all the updates. This works fantastically well!
# Posted By impressthenet.com | 10/16/09 4:51 PM
thetoolman's Gravatar Thanks for this, but I'd like to point out that the answer to the original question ( how to go about "Unselecting Radio Buttons with jQuery") is a one-liner inside your very verbose example:

$("input[name='radioName']").attr('checked', false);

The rest of your example is tooling for allowing unselect via keypress etc. I have a separate event needing to unselect, so the key/mouse stuff is unneeded.
# Posted By thetoolman | 1/14/10 5:58 PM
Jason Dean's Gravatar @thetoolman,

yeah, ok, thanks
# Posted By Jason Dean | 1/14/10 6:13 PM
Mariusz Kulerski's Gravatar Last thing, if you know, you're using ids, you can escape special chars like '.' or ':'.
So line
e.target = $('#' + $(this).attr("for"));
might became
e.target = $('#' + $(this).attr("for").replace(/(:|\.)/g,'\\$1'));

BTW: great script!
# Posted By Mariusz Kulerski | 4/26/10 5:29 AM
patrick rietveld's Gravatar The following code works like a charm:

$(document).ready(function() {
$("input[type='radio']").mousedown(function(e) {
if ($(this).attr("checked") == true) {
setTimeout("$('input[id=" + $(this).attr('id') + "]').removeAttr('checked');", 200);}
else {
return true
}
});
});
# Posted By patrick rietveld | 10/1/10 6:08 AM
chroniclemaster1's Gravatar This is a beautiful little module. Streamlined, efficient and you've done a fantastic job of responding to feedback and suggestions to make it even better.

I especially like that it functions transparently. All i needed to do was copy this code, drop it into my run-time code, and everything just works. Label-clicking, keyboard, everything. Everyone's done a fantastic job.
# Posted By chroniclemaster1 | 2/8/11 1:43 PM
Chip's Gravatar This script worked right out of the box for me. Thanks for your efforts here. It really helped me out.
# Posted By Chip | 3/18/11 9:33 AM
James's Gravatar As of jQuery 1.6 attr('checked') has been moved to prop('checked')

instead of attr('checked', false) you need to use removeProp('checked')
# Posted By James | 5/19/11 2:42 PM
CyberWomble's Gravatar Script does not work in IE9 as the keydown event target is the current radio button not the next one.
# Posted By CyberWomble | 9/2/11 7:45 PM
Armani's Gravatar Thanks man,
you saved my day. i used the code provided by jinxdone, Thanks jinxdone.
# Posted By Armani | 10/17/11 3:58 PM
AccessDenied's Gravatar Great work!

Works like a charm when you use the standard radio buttons, but I need to use whit radio buttons and jqueryUI, with the .buttonset() ...

any help? thanks in advance.
# Posted By AccessDenied | 12/11/11 10:07 AM
Aparna's Gravatar The code is really helpfull.
# Posted By Aparna | 3/9/12 3:51 AM
João Paulo's Gravatar thanks
very good !!
# Posted By João Paulo | 4/16/12 4:48 PM
Shane Mitchell's Gravatar I had a client ask just for the same thing - and while checkboxes are tempting - for the same functionality they would require the same (if not more) code. This solution works absolutely excellently... at least in Chrome/IE9. My client uses a Samsung tablet so if it doesn't work.. well.. you'll be the first to know! ;) [except me of course]
# Posted By Shane Mitchell | 8/22/12 5:30 AM
mhume's Gravatar I use a method utilising the data properties of the radio buttons
It proves for very succinct code
A working example can be found here http://jsfiddle.net/KmBjJ/
mh
# Posted By mhume | 5/29/13 1:14 PM
bbertout's Gravatar Help me a lot ! Great work, thank you !
# Posted By bbertout | 3/3/14 5:07 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner