Radio buttons are meant to be used in groups, as defined by their sharing the same name attribute. Then clicking on one of them deselects the currently selected one. To allow the user to cancel a “real” selection he has made, you can include a radio button that corresponds to a null choice, like “Do not know” or “No answer”.
If you want a single button that can be checked or unchecked, use a checkbox.
It is possible (but normally not relevant) to uncheck a radio button in JavaScript, simply by setting its checked property to false, e.g.
Here's an example of where it is arguably appropriate to uncheck radio buttons other than by making a new selection. I have a dictionary whose entries can be selected using a variety of indices. Which index to use is selected by means of a set of radio buttons. However, there is also a "random entry" button that the user can use if he or she just wants to browse. Leaving an index in place when the entry has been selected by means of the random entry button would be misleading, so when this button is pressed, I uncheck all of the index selection radio buttons and replace the contents of the index frame with an empty page.
As radio button mostly used in group, its a lot easier to grab them by getElementsByName( ' ' ); in your script tag. This will return an array, put an event listener on each array child and set the check state. Look at this sample.
var myRadios = document.getElementsByName('subscribe');
var setCheck;
var x = 0;
for(x = 0; x < myRadios.length; x++){
myRadios[x].onclick = function(){
if(setCheck != this){
setCheck = this;
}else{
this.checked = false;
setCheck = null;
}
};
}
This is my answer (though I made it with jQuery but only for the purpose of selecting elements and to add and remove a class, so you can easily replace it with pure JS selectors & pure JS add attribute )
Extending user3716078's answer to allow multiple independent radio button groups and a neater way of assigning event listeners to multiple elements...
window.onload = function() {
var acc_checked=[];
[].slice.call(document.querySelectorAll('.accordion input[type="radio"]')).forEach(function(el,i){
/**
* i represents the integer value of where we are in the loop
* el represents the element in question in the current loop
*/
el.addEventListener('click', function(e){
if(acc_checked[this.name] != this) {
acc_checked[this.name] = this;
} else {
this.checked = false;
acc_checked[this.name] = null;
}
}, false);
});
}
I came here because I had the same issue. I wanted to present the options to the user while leaving the option of remaining empty. Although this is possible to explicitly code using checkboxes that would complicate the back end.
Having the user Control+click is almost as good as having them uncheck it through the console. Catching the mousedown is to early and onclick is too late.
Well, at last here is a solution! Just put these few lines once on the page and you have it made for all radio buttons on the page. You can even fiddle with the selector to customize it.
<input type=radio name=unchecksample> Number One<br>
<input type=radio name=unchecksample> Number Two<br>
<input type=radio name=unchecksample> Number Three<br>
<input type=radio name=unchecksample> Number Four<br>
<input type=radio name=unchecksample> Number Five<br>
Unfortunately it does not work in Chrome or Edge, but it does work in FireFox:
$(document)
// uncheck it when clicked
.on("click","input[type='radio']", function(){ $(this).prop("checked",false); })
// re-check it if value is changed to this input
.on("change","input[type='radio']", function(){ $(this).prop("checked",true); });
Old question but people keep coming from Google here and OP asked preferably without jQuery, so here is my shot.
Should works even on IE 9
// iterate using Array method for compatibility
Array.prototype.forEach.call(document.querySelectorAll('[type=radio]'), function(radio) {
radio.addEventListener('click', function(){
var self = this;
// get all elements with same name but itself and mark them unchecked
Array.prototype.filter.call(document.getElementsByName(this.name), function(filterEl) {
return self !== filterEl;
}).forEach(function(otherEl) {
delete otherEl.dataset.check
})
// set state based on previous one
if (this.dataset.hasOwnProperty('check')) {
this.checked = false
delete this.dataset.check
} else {
this.dataset.check = ''
}
}, false)
})
But If I check a radio button, then check another and try to check the first one again I must do two clicks. This is because it has the class imChecked. I just needed to uncheck the other radio buttons before the verification.
Let's suppose you have a button where on clicking it, you can make all your radio button selection to false. You can write the below code inside the onclick handler.
Below code take radio buttons based on class name and for each element it will mark it to false.
var elements=document.getElementsByClassName('Button');
Array.prototype.forEach.call(elements, function(element) {
element.checked = false;
});
You cannot easily implement uncheck trivially via if(this.checked) this.checked = false, (if you really want to, see the hacker way at the end) because the events fire in this order:
mousedown or keydown
mouseup or keyup
if not checked, set the checked property now
click
input (only if state is changed)
change (only if state is changed)
Now in which event to perform the mentioned uncheck?
mouseup or mousedown: then in the step 3 the value is set back to true and change and input event doesn't even fire as the state didn't change when they are called in the sequence - so you can't uncheck it here
click: then the state is always false and input and change also doesn't fire - so you can't check it
input or change: it doesn't fire when the state is not changed and clicking selected element doesn't change the state - so you can't do anything useful here
The naive way
As you can learn from the sequence above, the way is:
read the previous state in mouseup
set the state in click as negation of previous state
If you want to store the previous state in data attribute, keep in mind that it is saved as string, whereas the checked attribute is boolean. So you can implement it like:
It seemingly works, but you should not do this for these reasons:
the user may mousedown somewhere else, then hover above radio button, then mouseup: in this case mouseup fires and click does not
the user may use Tab to focus radio group, then arrows to change: mouseup doesn't fire and click does
The proper way
There is another issue: dynamically added radio buttons. There are two ways:
element.appendChild(radio) - if you enable deselect on all radios in DOMContentLoaded event, this dynamically added radio is not affected
element.innerHTML+= '<input type="radio">' - effectively replaces the HTML contents of the element and re-creates DOM inside it - so all event listeners are discarded
To solve (2), I recommend onclick content attribute. Note that element.onclick = fn and element.setAttribute("onclick", "fn()") are two different things. Also note that onclick fires everytime the user activates the radio, regardless of the interface he used.
Yet another issue: if you enable deselect, then you should also enable switching by Space to mimic checkboxes behaviour. The following code solves all mentioned issues:
Now you can call deselectableRadios() anytime you dynamically add content and calling it on radios multiple times doesn't break it. You can also specify the rootElement to update only a subtree of HTML DOM and make your web faster. If you don't like the global state, you can use the hacker way:
The hacker way
The point is to abuse setTimeout on mouseup to call it after the checked property is set:
However, the radio value is now defined as compat-auto type which is treated like auto, i.e. no visual change. It seems that there will be no progress here in the future.
This works for single form. If you have multiple form with the class="radio", then once you click on a radio button, the others are disabled. Use this if that's what you want.
Now I wanted to implement this on my rails project, which has multiple forms (depends, fetched from database), each form has 2 visible radio buttons + 1 hidden radio button.
I want the user the select / deselect the radio button of each form. And selecting one on a form shouldn't deselect the other selected button on another form. So I rather did this:
var radios = Array.from(document.getElementsByClassName('radio'))
for (let i of radios) {
i.state = false
i.onclick = () => {
i.checked = i.state = !i.state
for (let j of radios)
if (j !== i) j.state = false
}
}
Most of the modern day browsers consider checked="anything" as checked="true".
You might have to remove the checked attribute if that makes sense in your case, one of which might be related to when you load the page.
$(this).removeAttr('checked')
This might help you in cases when you want your radio button to be checked adhering to some condition. You can simply remove the attribute to achieve that.
I'm surprised no-one has posted this "neat trick" version which doesn't use any JavaScript, it only uses CSS.
#radio1 {
display: none;
}
#wrapper {
/* NOTE: This wrapper div is not needed provided you can position the label for #radio1 on top of #radio2 using some other technique. */
position: relative;
}
#radio1:not(:checked) ~ * label[for="radio1"] {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#radio1:checked ~ * label[for="radio1"] {
display: none;
}
/* Non-essential styles: */
label[for],
label:not([for="radio1"]) {
cursor: pointer;
border-radius: 7px;
}
label[for]:hover + label,
label:not([for="radio1"]):hover {
background-color: #ccc;
}
<input type="radio" name="group1" id="radio1" checked="checked" />
<p>Look mum, <strong>no JavaScript!</strong></p>
<div id="wrapper">
<label for="radio1"></label>
<label>
<input type="radio" name="group1" id="radio2" />
You can toggle me on and off!
</label>
</div>
Explanation:
#radio1 (<input type="radio" id="radio2" />) is always hidden.
Using CSS's :checked and :not(:checked) pseudo-class selectors with sibling selectors (+ and ~) allow other elements' style to be affected depending on whether or not an <input type="checkbox" /> or <input type="radio" /> is checked.
So when #radio1 is un-checked (or when #radio2 is checked) that causes a <label> to be overlayed on-top of #radio2 and that label has for="radio1", so clicking it will cause #radio1 to be checked, not #radio2.
IMPORTANT CAVEAT: CSS's sibling selector rules only allows selectors to select elements based on their ancestors and their ancestors earlier siblings. So you cannot style an element based on any other descendants of its ancestors.
This limitation will be removed when CSS4's :has() selector function is supported but as of November 2020 only PrinceXML supports :has() and it's currently looking like :has() will be dropped from CSS4 entirely owing to the difficulty of implementation.
This approach can be scaled to support multiple radio buttons:
I know It's very late (even unnecessary now) and there are many solutions here, but I couldn't find any specific to the question asked or there is so much code in them for this simple scenario, one can easily ignore it while looking for an answer.
So here, I am proposing my solution as It might help any newcomer. The idea is simple, just
Set the same class on required toggles in my case its "toggles"
Get the current value of the toggle on mouse hover action
Inverse the toggle value.
By this either you can select any of the toggles or completely ignores them but clicking again on the already selected toggle. You can also test this with the given snippet.
var val;
$('.toggles').mouseup(function(){
val = this.checked
}).click(function(){
this.checked = val == true ? false : true
})
I had this issue and my solution was rather simple, I just made them into checkboxes and when one checkbox was toggled, I deselected all the other checkboxes in the group.
I know it is a bit hacky, and has a large big O complexity (although n is small), but it works! (todo: think of more original names for variables)
$(document).ready(function() {
$("input[name=days]").each((_, el) => {
el.addEventListener("click", function () {
$("input[name=days]").each((_, myEl) => {
if (el != myEl) {
myEl.checked = false;
}
});
// Do other stuff
});
});
});
sorry if my answer is already answered but honestly i read them all very quickly because there are so many
i am not so skilled, but i think i found a VERY SIMPLE way to uncheck an already checked radio button just by click it again... just with a global var, a little function, and onclick event