Radio and Radio Group
Radio and Radio Group
Overview
It is always best to provide native HTML radio buttons, rather than custom radio buttons, but when coded correctly, the custom buttons can and should act like native HTML radio buttons.
Turn on a screen reader to experience this example in action.
Which one of these scientists most inspires you?
Marie Curie
Jane Goodall
Rosalind Franklin
Hedy Lamarr
HTML Source Code
<!--div role="radiogroup" aria-labelledby="group_label_1" id="rg1">
<h2 id="group_label_1">What's your favorite framework?</h2>
<div role="radio" aria-checked="false" tabindex="0">React</div>
<div role="radio" aria-checked="false" tabindex="-1">Angular</div>
<div role="radio" aria-checked="false" tabindex="-1">Vue</div>
<div role="radio" aria-checked="false" tabindex="-1">Ember</div>
<div role="radio" aria-checked="false" tabindex="-1">None</div>
</div-->
<div >
<!--h2 id="group_label_1">What's your favorite framework?</h2-->
<fieldset>
<legend>What's your favorite framework?</legend>
<input type="radio" id="react" name="fav_language" value="React">
<label for="react">React</label><br>
<input type="radio" id="angular" name="fav_language" value="Angular">
<label for="angular">Angular</label><br>
<input type="radio" id="vue" name="fav_language" value="Vue">
<label for="vue">Vue</label><br>
<input type="radio" id="none" name="fav_language" value="None">
<label for="none">None</label><br>
</fieldset>
</div>
<div role="radiogroup" aria-labelledby="group_label_2" id="rg2">
<h3 id="group_label_2">Which one of these scientists most inspires you?</h3>
<div role="radio" aria-checked="false" tabindex="0">Marie Curie</div>
<div role="radio" aria-checked="false" tabindex="-1">Jane Goodall</div>
<div role="radio" aria-checked="false" tabindex="-1">Rosalind Franklin</div>
<div role="radio" aria-checked="false" tabindex="-1">Hedy Lamarr</div>
</div>
<!---
This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License http://www.w3.org/copyright/software-license-2023/
-->
JavaScript Source Code
class RadioGroup {
constructor(groupNode) {
this.groupNode = groupNode;
this.radioButtons = [];
this.firstRadioButton = null;
this.lastRadioButton = null;
var rbs = this.groupNode.querySelectorAll('[role=radio]');
for (var i = 0; i < rbs.length; i++) {
var rb = rbs[i];
rb.tabIndex = -1;
rb.setAttribute('aria-checked', 'false');
rb.addEventListener('keydown', this.handleKeydown.bind(this));
rb.addEventListener('click', this.handleClick.bind(this));
rb.addEventListener('focus', this.handleFocus.bind(this));
rb.addEventListener('blur', this.handleBlur.bind(this));
this.radioButtons.push(rb);
if (!this.firstRadioButton) {
this.firstRadioButton = rb;
}
this.lastRadioButton = rb;
}
this.firstRadioButton.tabIndex = 0;
}
setChecked(currentItem) {
for (var i = 0; i < this.radioButtons.length; i++) {
var rb = this.radioButtons[i];
rb.setAttribute('aria-checked', 'false');
rb.tabIndex = -1;
}
currentItem.setAttribute('aria-checked', 'true');
currentItem.tabIndex = 0;
currentItem.focus();
}
setCheckedToPreviousItem(currentItem) {
var index;
if (currentItem === this.firstRadioButton) {
this.setChecked(this.lastRadioButton);
} else {
index = this.radioButtons.indexOf(currentItem);
this.setChecked(this.radioButtons[index - 1]);
}
}
setCheckedToNextItem(currentItem) {
var index;
if (currentItem === this.lastRadioButton) {
this.setChecked(this.firstRadioButton);
} else {
index = this.radioButtons.indexOf(currentItem);
this.setChecked(this.radioButtons[index + 1]);
}
}
/* EVENT HANDLERS */
handleKeydown(event) {
var tgt = event.currentTarget,
flag = false;
switch (event.key) {
case ' ':
this.setChecked(tgt);
flag = true;
break;
case 'Up':
case 'ArrowUp':
case 'Left':
case 'ArrowLeft':
this.setCheckedToPreviousItem(tgt);
flag = true;
break;
case 'Down':
case 'ArrowDown':
case 'Right':
case 'ArrowRight':
this.setCheckedToNextItem(tgt);
flag = true;
break;
default:
break;
}
if (flag) {
event.stopPropagation();
event.preventDefault();
}
}
handleClick(event) {
this.setChecked(event.currentTarget);
}
handleFocus(event) {
event.currentTarget.classList.add('focus');
}
handleBlur(event) {
event.currentTarget.classList.remove('focus');
}
}
// Initialize radio button group
window.addEventListener('load', function () {
var radios = document.querySelectorAll('[role="radiogroup"]');
for (var i = 0; i < radios.length; i++) {
new RadioGroup(radios[i]);
}
});
//This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License http://www.w3.org/copyright/software-license-2023/
CSS Source Code
[role="radiogroup"] {
padding: 0;
margin: 0;
list-style: none;
}
[role="radiogroup"]:focus {
outline: none;
}
[role="radio"] {
padding: 4px 8px;
border: 0 solid transparent;
border-radius: 5px;
display: inline-block;
position: relative;
cursor: default;
outline: none;
color: black;
}
[role="radio"] + [role="radio"] {
/* margin-left: 1em; */
}
[role="radio"]::before {
position: relative;
top: 1px;
margin: 5px;
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='14' width='14' style='forced-color-adjust: auto;'%3E%3Ccircle cx='7' cy='7' r='6' stroke='rgb(0, 90, 156)' stroke-width='2' fill-opacity='0' /%3E%3C/svg%3E");
}
[role="radio"][aria-checked="true"]::before {
position: relative;
top: 1px;
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='14' width='14' style='forced-color-adjust: auto;'%3E%3Ccircle cx='7' cy='7' r='6' stroke='rgb(0, 90, 156)' stroke-width='2' fill-opacity='0' /%3E%3Ccircle cx='7' cy='7' r='3' fill='rgb(0, 90, 156)' stroke-opacity='0' /%3E%3C/svg%3E");
}
[role="radio"].focus,
[role="radio"]:hover {
padding: 2px 6px;
border: 2px solid #005a9c;
background-color: #def;
cursor: pointer;
}
.radio-container { display: block;}
/*
This component has been adapted from an example provided by the W3C, in accordance with the W3C Software and Document License http://www.w3.org/copyright/software-license-2023/
*/