3

I would like to know how to theme Drupal 7 Webform elements? I want to change the HTML structure of every element, not just wrap form with div or something like that. And I want to leave theme's elements as they were.

EDIT: I would like to add class to label and input type radio button.

5
  • 1
  • I have already checked those threads. The theming.txt doesn't say anything about form elements, just whole form, etc.. So does the first link you gave. Example: i would like to edit label's style .
    – gregab
    May 29, 2013 at 9:41
  • then what the problem you are facing? May 29, 2013 at 9:43
  • I don't know how to do that :) Style form element just for webforms, not the whole theme ..
    – gregab
    May 29, 2013 at 9:45
  • +1 useful question - and answer below. Thank you. In my case I needed to insert autocomplete=off in the confirm email field, so that the user had to type out the email again, rather than rely upon pre-fill from previous form submissions. Jul 24, 2014 at 12:00

1 Answer 1

19

Each webform element has it's own file in the "components" sub-directory of the webform module folder.

If you look in those files there is a _webform_theme_COMPONENTTYPE() function, for example _webform_theme_date() for the date fields.

This function defines the theme functions for that field type.

These theme functions are what you can use to override the themeing of the fields.

For exmaple theme_webform_date() can be overridden as THEMENAME_webform_date(&$variables) and you can change the output.

If it is things like the field wrappers or labels you want, then look at overriding the theme_webform_element() function.

That will let you do things like change where the label is printed in relation to the field.

You can use $element['#type'] to single out specific field types in that theme function.

Note: Webform components are a special case. Normally you can find themeable things by looking in the MODULENAME_theme() function. In this case webform_theme().

Specifically, to set classes on radio button fields:

You requirement of adding the class to a radio button is unfortunately a bit different. This is because webform doesn't use it's own themeing, it uses drupal core's

So what you want is theme_radios() and/or theme_radio() and/or theme_form_element_label().

Something like these (there are comments to tell you what has changed):

/**
 * Theme a set of radio buttons.
 */
function THEMENAME_radios($variables) {
  $element = $variables['element'];
  $attributes = array();
  if (isset($element['#id'])) {
    $attributes['id'] = $element['#id'];
  }
  $attributes['class'] = 'form-radios';
  if (!empty($element['#attributes']['class'])) {
    $attributes['class'] .= ' ' . implode(' ', $element['#attributes']['class']);
  }
  if (isset($element['#attributes']['title'])) {
    $attributes['title'] = $element['#attributes']['title'];
  }

  // Add custom classes.
  // To target specific elements you can use the $element variable.
  // You can target the label using:
  // .your-custom-class label
  $attributes['class'] .= 'your-custom-class another-custom-class';

  return '<div' . drupal_attributes($attributes) . '>' . (!empty($element['#children']) ? $element['#children'] : '') . '</div>';
}

/**
 * Theme a single radio button.
 */
function THEMENAME_radio($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'radio';
  element_set_attributes($element, array('id', 'name','#return_value' => 'value'));

  if (isset($element['#return_value']) && $element['#value'] !== FALSE && $element['#value'] == $element['#return_value']) {
    $element['#attributes']['checked'] = 'checked';
  }
  _form_set_class($element, array('form-radio'));

  // Set custom classes.
  // Use $element to target specific fields.
  $element['#attributes']['class'][] = 'your-custom-class';
  $element['#attributes']['class'][] = 'another-custom-class';

  return '<input' . drupal_attributes($element['#attributes']) . ' />';
}

Unfortunately it is not possible to add classes to a label except for overriding theme_form_element_label() because of this bug.

The are two possible ways to address this in the theme layer.

One is to add the class to the field wrapper and then target the labels via that in your css or js.

The other is to override theme_form_element_label() like this:

/**
 * Theme a form element label.
 */
function THEMENAME_form_element_label($variables) {
  $element = $variables['element'];
  // This is also used in the installer, pre-database setup.
  $t = get_t();

  // If title and required marker are both empty, output no label.
  if ((!isset($element['#title']) || $element['#title'] === '') && empty($element['#required'])) {
    return '';
  }

  // If the element is required, a required marker is appended to the label.
  $required = !empty($element['#required']) ? theme('form_required_marker', array('element' => $element)) : '';

  $title = filter_xss_admin($element['#title']);

  $attributes = array();
  // Style the label as class option to display inline with the element.
  if ($element['#title_display'] == 'after') {
    // Changed to make class an array.
    $attributes['class'][] = 'option';
  }
  // Show label only to screen readers to avoid disruption in visual flows.
  elseif ($element['#title_display'] == 'invisible') {
    // Changed to make class an array.
    $attributes['class'][] = 'element-invisible';
  }

  if (!empty($element['#id'])) {
    $attributes['for'] = $element['#id'];
  }

  // Add your classes here.
  // If you are using variables to make the class use the drupal_html_class()
  // function.
  // To target specific elements you can use the $element variable.
  // For example, based on field type:
  if ($element['#type'] == '') {
    $attributes['class'][] = 'your-custom-class';
    $attributes['class'][] = 'another-custom-class';
  }

  // The leading whitespace helps visually separate fields from inline labels.
  return ' <label' . drupal_attributes($attributes) . '>' . $t('!title !required', array('!title' => $title, '!required' => $required)) . "</label>\n";
}
8
  • Added a little note to the end of the answer.
    – rooby
    May 29, 2013 at 10:22
  • It looks to me that everything is connected to form's theme and i don't see where i could change the output html.
    – gregab
    May 29, 2013 at 10:46
  • Radio buttons, for example..
    – gregab
    May 29, 2013 at 10:52
  • Anything is possible :) What specifically do you want to do? (maybe add it to the question instead of a comment here.)
    – rooby
    May 29, 2013 at 11:25
  • Update coming shortly.
    – rooby
    May 29, 2013 at 11:45

Your Answer

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

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