The modern way of checking radio groups

Checking radio groups in JavaScript has always been a bit tricky because you can only check if a particular radio button is selected, not the whole group at once.

<input type="radio" name="fruits" id="banana" checked="checked" />Banana
<input type="radio" name="fruits" id="apple" />Apple
<input type="radio" name="fruits" id="cherry" />Cherry
const fruits = document.getElementsByName('fruits');
var selectedFruit = '';
for (var i = 0; i < fruits.length; ++i) {
  if (fruits[i].checked) {
    selectedFruit = fruits[i].id;
  }
}

Wow, that looks archaic. There must be a better way using the new ES6 features, and there is! As of ES2015, NodeList contains a forEach method(). This makes things much easier:

var fruits = document.getElementsByName('fruits');
let selectedFruit = '';
fruits.forEach((fruit) => {
  if (fruit.checked) {
    selectedFruit = fruit.id;
  }
});

Still a lot of lines. We can make the code much tighter, but also much more unreadable:

[…document.getElementsByName('fruits')].some(
  (fruit) => (selectedFruit = fruit.id) && fruit.checked
);

This requires a bit of explanation, because in order to achieve it we have to dig deep into our bag of tricks.

First we convert the NodeList to an array using the spread operator to have all the funky Array() methods available.
The Array() method we use is some(). This method loops over an array until the callback function returns true. In our case we exit the loop by checking for “fruit.checked” which is true if the radio button is checked.

The second trick is to include the assignment of the loop variable fruit to the variable selectedFruit. This assignment always returns true, and therefore does not affect the result of the whole statement when it’s linked with && operator to the other comparison.

BTW, we don’t need to declare an upper scope variable any more here because we don’t enter a new scope in the callback function. New scopes require curly braces which we don’t need here because the callback function only contains a single statement.
You can be picky and point our that selectedFruit is undeclared, but the code works nevertheless. So what?

Conclusion
We reduced the code from six lines to three and from 193 to 115 characters. Not bad and your code will look much cooler on GitHub!

Edit
I published this post on dev.to and Jon Randy added some interesting stuff:

Shorter:

let selectedFruit = [...document.getElementsByName('fruits')].find(({checked}) => checked).id

Shorter still:

let selectedFruit = document.querySelector('[name=fruits][checked]')?.id