8

By default, the HTML markup for radio buttons looks like (Drupal 7):

<div class="form-item form-type-radio form-item-SOME_ID">
  <input id="edit-SOME_ID" class="form-radio" type="radio" value="SOME_VALUE" name="SOME_NAME" /> 
  <label class="option" for="edit-bla-bla">MY LABEL</label>
</div>

I need to change/add some css classes in the outer <div> OR add a wrapper <div>. How do I do that?

3
  • 1
    Did you ever figure out how to do this?
    – nanobar
    Commented Nov 5, 2012 at 11:53
  • did you find the answer actually were the same looking for answer for this changing wrapper attributes around each radio button.. please reply.. thanks
    – user12494
    Commented Jan 5, 2013 at 5:50
  • I wonder if you might clarify where the -SOME_ID is coming from in your "by default" Drupal theming of radios. To level the variables, I switched to Seven theme and still see only the ID of the radios group, not a wrapper on each item :( Commented Jun 12, 2013 at 21:31

4 Answers 4

9

If you're defining the form yourself you can wrap an element with HTML using the #prefix and #suffix properties:

$form['radios'] = array(
  '#type' => 'radios',
  '#title' => 'Options',
  '#options' => drupal_map_assoc(1, 2, 3),
  '#prefix' => '<div class="some-class">',
  '#suffix' => '</div>'
);

If you want to add a class to the existing wrapper you can do so using the #attributes property:

$form['radios'] = array(
  '#type' => 'radios',
  '#title' => 'Options',
  '#options' => drupal_map_assoc(1, 2, 3),
  '#attributes' => array(
    'class' => array('some-class')
  )
);

If you're not defining the form yourself then you can still use the same logic and implement a hook_form_alter() to change the existing form:

function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'some_form_id') {
    $form['some_element']['#attributes']['class'][] = 'some-class';
  }
}

Note that when using the hook_form_alter() method you should append to the existing classes array so as not to override any classes that have been set previously.

4
  • 6
    I mean wrapper around each radio button, not group
    – volocuga
    Commented Feb 19, 2012 at 20:12
  • 1
    This does it for the entire group of radios not the individual radio buttons.
    – DrCord
    Commented Aug 27, 2015 at 20:07
  • From your comment, If you wanted around each radio button @volocuga then why, as original poster of the question, did you accept this answer? Or did this answer do what you actually needed? Commented Nov 9, 2020 at 22:37
  • @therobyouknow Good question after 8 years. Sorry I don't recall all details
    – volocuga
    Commented Nov 11, 2020 at 6:30
1

I was able to achieve this after much work and trying every posted method using a smart tip I found deep in the internet on another site: http://e9p.net/altering-individual-radio-or-checkbox-items-drupal-7-fapi, to use #after_build to be able to alter the form element individual radios once they are a drupal render array.

I wanted each radio wrapped in a container with a class, so I used #prefix and #suffix to do that:

function _MYMODULE_options_after_build(&$element, &$form_state){
    // Each renderable radio element.
    foreach (element_children($element) as $key) {
        $element[$key]['#prefix'] = '<div class="class1 class2">';
        $element[$key]['#suffix'] = '</div>';
    }
    // Always return the element to render in after_build callbacks.
    return $element;
}

example use:

$form['style'] = array(
        '#type' => 'radios',
        '#title' => t('Select your style option'),
        '#options' => $style_options,
        '#default_value' => NULL,
        '#required' => TRUE,
        '#after_build' => array(
            '_MYMODULE_options_after_build'
        )
);

However if you only want the input element to have the class you would need to implement the solution I posted on drupal.org at https://api.drupal.org/comment/60197#comment-60197 to allow the #options_attributes to be used correctly for individual options. Re-posting code here:

function MYMODULE_element_info_alter(&$info) {
    // You might want more advanced logic here, to replace instead of override altogether,
    // in case other modules have already altered the core info.
    $info['radios']['#process'] = array('safetycal_request_a_quote_process_radios');
}

function MYMODULE_process_radios($element) {
    // for some reason when I take over processing the radios the structure
    // is slightly different than with form_process_radios and it needs to be fixed
    if(isset($element['element'])){
        $element = $element['element'];
    }
    if (count($element ['#options']) > 0) {
        $weight = 0;
        foreach ($element ['#options'] as $key => $choice) {
            // Maintain order of options as defined in #options, in case the element
            // defines custom option sub-elements, but does not define all option
            // sub-elements.
            $weight += 0.001;

            $element += array($key => array());
            // Generate the parents as the autogenerator does, so we will have a
            // unique id for each radio button.
            $parents_for_id = array_merge($element ['#parents'], array($key));
            $element [$key] += array(
                '#type' => 'radio',
                '#title' => $choice,
                // The key is sanitized in drupal_attributes() 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,
                // changed below line to use the #options_attributes array
                '#attributes' => $element['#option_attributes'][$key],
                '#parents' => $element ['#parents'],
                '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
                '#ajax' => isset($element ['#ajax']) ? $element ['#ajax'] : NULL,
                '#weight' => $weight,
            );
        }
    }
    return $element;
}

example use:

$style_options = array(
    'red' => 'Red',
    'green' => 'Green',
    'yellow' => 'Yellow'
);
$style_option_attributes = array(
    'red' => array(
        'class' => array(
                'red-class'
            )
    ),
    'green' => array(
        'class' => array(
                'green-class'
            )
    ),
    'yellow' => array(
        'class' => array(
                'yellow-class'
            )
    )
);
$form['style'] = array(
    '#type' => 'radios',
    '#title' => t('Select your style option'),
    '#options' => $style_options,
    '#option_attributes' => $style_option_attributes,
    '#default_value' => NULL,
    '#required' => TRUE,
    '#attributes' => array(
        'class' => array(
            'radio-element-class'
        )
    )
 );
0

You can do the above(prefix/suffix) on the items in the options array then you get anything you want around each item.

$form['view_mode'] = array(
    '#type' => 'radios',
    '#default_value' => isset($_GET['view'])?$_GET['view']:1,
    '#options' => array(
          1 => '1',
          2 => '2',
          3 => '3',
    ),
  ),
);
$form['view_mode'][1] = array(
    '#prefix' => '<div class="first-item container">',
    '#suffix' => '</div>'
);
3
  • 1
    I want to believe, but this is not doing it for me (D7). Instead, it just stuffs in the prefix+suffix as a sibling element immediately preceding the individually div-wrapped options elements. Could it be a typo, and there really is a way? Commented Apr 7, 2015 at 14:12
  • Sounds just like you are adding the div to a none existing option. Think you have to make sure options array values match each other. Commented Apr 8, 2015 at 16:40
  • This definitely does what texas-bronius says, adds a separate element at the same level as the radio buttons, not a working solution, sadly.
    – DrCord
    Commented Aug 27, 2015 at 20:08
0

The only way I have been able to achieve this is by creating a different form element for each radio, manually pairing up the names using #name and manually setting a value using #attributes. (#value doesn't work for some reason.)

For example:

$form['apple'] = array(
  '#type' => 'radio', // Notice no s here; 'radio' not 'radios'
  '#name' => 'fruit', // This will ensure the radios are in the same group
  '#attributes' => array(
       'value' => 'apple', // I know this is bad but it's the only way I could get setting a value to work
       'class' => 'class_here' // This will add class_here to the default wrapper
   ),
  '#prefix' => '<div class="some-class">', // This will prefix the individual radio, wrapper and label
  '#suffix' => '</div>' // This will suffix the individual radio, wrapper and label
);

// Then just repeat with different values

$form['orange'] = array(
  '#type' => 'radio',
  '#name' => 'fruit', // Same name
  '#attributes' => array(
       'value' => 'orange', // Different value
       'class' => 'class_here'
   ),
  '#prefix' => '<div class="some-class">',
  '#suffix' => '</div>'
);

$form['banana'] = array(
  '#type' => 'radio',
  '#name' => 'fruit', // Same name
  '#attributes' => array(
       'value' => 'banana', // Different value
       'class' => 'class_here'
   ),
  '#prefix' => '<div class="some-class">',
  '#suffix' => '</div>'
);

This will add a wrapper and class to the individual radio buttons rather than the radio group as the currently accepted answer does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.