I was never too happy about being forced to aim at that tiny radio button, so I came up with a larger target AND a way to turn a radio group off without resorting to anything that would upset the HTML / JavaScript purists.
The technique relies on not molesting the radio buttons at all via event handlers, but checking for a readonly proxy for each one instead. Everything is contained in what's below in pure JavaScript using a radio group to select a type of cheese, or no cheese at all.
I purposely used no styling in this example to avoid that added layer. The dump button will tell you what the three checked states are, so use it to interrogate what happened after hitting the radio or text input elements. For example simplicity I used a global to remember the former state, but a more elegant method is to use a dataset, which I what I use in the real code of my application.
<!DOCTYPE html>
<html>
<head>
<title>Uncheck a radio button</title>
<script>
function attachEventListener(target, eventType, functionRef, capture) {
"use strict";
if (typeof target.addEventListener !== 'undefined') {
// Most modern browsers
target.addEventListener(eventType, functionRef, capture);
} else if (typeof target.attachEvent !== 'undefined') {
// IE
target.attachEvent('on' + eventType, functionRef);
} else {
eventType = 'on' + eventType;
if (typeof target[eventType] === 'function') {
var oldListener = target[eventType];
target[eventType] = function() {
oldListener();
return functionRef();
};
} else {
target[eventType] = functionRef;
}
}
}
</script>
</head>
<body>
<form>
<input id="Cheddar-radio" class="radio" type="radio" name="Cheeses-0" value="Cheddar Cheese" tabindex="-1"></input>
<input id="Cheddar-text" type="text" readonly value="Cheddar Cheese" tabindex="-1"></input><br>
<input id="Swiss-radio" class="radio" type="radio" name="Cheeses-0" value="Swiss Cheese" tabindex="-1"></input>
<input id="Swiss-text" type="text" readonly value="Swiss Cheese" tabindex="-1"></input><br>
<input id="American-radio" class="radio" type="radio" name="Cheeses-0" value="American Cheese" tabindex="-1"></input>
<input id="American-text" type="text" readonly value="American Cheese" tabindex="-1"></input><br><br>
<input onclick="dumpStates()" type="button" name="button" value="dump" tabindex="-1"></input>
</form>
<script>
window.onload = addRadioListeners;
function addRadioListeners() { // But do it on the -text elements.
attachEventListener(document.getElementById('Cheddar-text') , 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('Swiss-text') , 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('American-text'), 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('Cheddar-text') , 'mouseup', checkNewState, false);
attachEventListener(document.getElementById('Swiss-text') , 'mouseup', checkNewState, false);
attachEventListener(document.getElementById('American-text'), 'mouseup', checkNewState, false);
}
function dumpStates() {
console.log(document.getElementById('Cheddar-radio').checked +
' ' + document.getElementById('Swiss-radio').checked +
' ' + document.getElementById('American-radio').checked);
}
var elementWasChecked; // Global - Could just as well use a dataset attribute
// on either the -radio or -text element and check it instead.
function rememberCurrentState(event) {
var element;
var radioElement;
element = event.target;
radioElement = document.getElementById(element.id.replace(/text/,'radio'));
elementWasChecked = radioElement.checked;
radioElement.checked = true;
}
function checkNewState(event) {
var element;
var radioElement;
element = event.target;
radioElement = document.getElementById(element.id.replace(/text/,'radio'));
var currentState = radioElement.checked;
if (elementWasChecked === true && currentState === true) {
console.log('Changing ' + radioElement.id + ' to false.');
radioElement.checked = false;
}
};
</script>
</body>
</html>
If you click on the radio buttons they work as expected. If you click on the text items next to each, they are a proxy for the radio buttons with one exception. If you click on a text item that has an associated radio button that's already checked, it will uncheck it. Therefore, the text proxy's are event triggered, and not the radio buttons.
The added benefit is that you can now hit the larger text target too.