Problem/Motivation
You somethings want some individual controle on attributes on single radio elements, especially with css and js interaction on the frontend. Using radios complicates this, and needs you to do all kinds of preprocessing around it instead of passing a radio item render array using the render array definition for radios.
Currently you can only do this:
$form['settings']['active'] = array(
'#type' => 'radios',
'#title' => $this->t('Poll status'),
'#default_value' => 1,
'#options' => array(0 => $this->t('Closed'), 1 => $this->t('Active')), #<--
);
While the single radio button generated within the "radios" element can have more attributes. But there is no way to pass that along currently in the radios element.
This is the processRadios function from Drupal\Core\Render\Element\Radios
foreach ($element['#options'] as $key => $choice) {
#... some stuff ...
$element[$key] += [
'#type' => 'radio',
'#title' => $choice,
// The key is sanitized in Drupal\Core\Template\Attribute during output
// from the theme function.
'#return_value' => $key,
// Use default or FALSE. A value of FALSE means that the radio button is
// not 'checked'.
'#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE,
'#attributes' => $element['#attributes'],
'#parents' => $element['#parents'],
'#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)),
'#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
// Errors should only be shown on the parent radios element.
'#error_no_message' => TRUE,
'#weight' => $weight,
];
You can only pass a $key $value ($choice) array along which should be int/strings. So no way to pass along unique attributes per radio items in radios.
Proposed resolution
Why not also allow do something like this:
$singleRadio = [
'#type' => 'radio',
// The key is sanitized in Drupal\Core\Template\Attribute during output
// from the theme function.
'#return_value' => $key,
// Use default or FALSE. A value of FALSE means that the radio button is
// not 'checked'.
'#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE,
'#attributes' => $element['#attributes'],
'#parents' => $element['#parents'],
'#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)),
'#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
// Errors should only be shown on the parent radios element.
'#error_no_message' => TRUE,
'#weight' => $weight,
];
if (is_array($choice)) {
$singleRadio = NestedArray:mergeDeep($singleRadio, $choice);
}
$singleRadio['#return_value'] = $key;
$element[$key] += $singleRadio;
That way we can allow the normal and more advanced method in a single element.
$form['settings']['active'] = array(
'#type' => 'advanced_radios',
'#title' => $this->t('Poll status'),
'#default_value' => 1,
'#options' => array(0 => ['#title' => $this->t('Closed'), '#attributes' => ['data-something' => 'example'], 1 => $this->t('Active')),
);