12

Is there a way to add or change a class to a form wrapper (the div's) using the form api?

Or is that just done with the theme function ?

If so which theme function is used to change that?

4
  • I'm pretty sure that's a theme function. Which theme function to use is the question. :)
    – akalata
    Sep 14, 2011 at 0:57
  • Ah you're right there.
    – chrisjlee
    Sep 14, 2011 at 1:25
  • I think you can also use the #attribute key to define a class
    – Mika A.
    Sep 14, 2011 at 7:25
  • 1
    @Mika A. This only applies to the <input> tag i'd like to change the class of the wrapper (a <div>).
    – chrisjlee
    Sep 14, 2011 at 18:28

8 Answers 8

5

You can override theme_form_element() normally if you want to change the theming globally. If you're interested in modifying just one specific form element then I'm aware of a couple of choices.

  1. You can register a new theme function for the particular type of form element you're interested in (eg. textfield). You then create this theme function (based on the original, eg. theme_textfield()) but that doesn't call theme('form_element', ...) at the end (you could either handle both the wrapper and the element in the one theme function, or you could make a separate wrapper theme function and use that). Finally you add a #theme property to a particular form element, and that element will get your custom theming.

  2. You can create a template file called form_element.tpl.php which just has the default behaviour of theme_form_element() and then use hook_preprocess_form_element() to add a template suggestion. Then you create the new template that matches the suggestion. You often hear people mentioning that templates are slightly slower than functions, and for such a frequently used theme call I can imagine people balking at using a template. I've never done any measurements for this myself however. Also, you need to have enough context at the preprocess stage to be able to make the suggestion.

4
  • Could you provide an example?
    – chrisjlee
    Jan 27, 2012 at 21:01
  • @ChrisJ.Lee Do you want to change the wrapper on all elements, or just one particular one?
    – Andy
    Jan 28, 2012 at 13:07
  • just a single one.
    – chrisjlee
    Feb 1, 2012 at 3:23
  • @chrisjlee I've updated the answer.
    – Andy
    Feb 1, 2012 at 13:47
7

You can use wrapper_attributes property.

$form['example'] = [
  '#type' => 'textfield',
  '#title' => $this->t('Example'),
  '#wrapper_attributes' => ['class' => ['wrapper-class']],
];
1
  • This answer helped me, but note that it applies specifically to Drupal 8.x and later. Feb 27, 2020 at 0:15
4

I know this is a super old thread, but I'v been learning how to alter form elements and add classes. I got around to making a custom module:

function yourtheme_custom_form_alter(&$form, &$form_state, $form_id) {
 case'webform_number_whatever':
   _yourtheme_form_add_wrapper($form['submitted']['yourfieldhere'], array('form-field-some-style', 'not-label', 'whatever-other-styles-you-want'));
 break;
}

function _yourtheme_form_add_wrapper(&$element, $classes = array(), $type = array('form-item', 'form-type-textfield'), $removeTitle = FALSE){
  $element['#prefix'] = '<div class="' . implode(" ", $classes) . '"><div class="' . implode(" ", $type) . '">';
  $element['#suffix'] = '</div></div>';
}
1
  • This is a good alternative solution - don't add a class to the wrapping div, just wrapping the wrapping div in your own div and they you can apply whatever classes you want.
    – Felix Eve
    Feb 11, 2014 at 15:10
3

To Change the "wrapper" you need to override form_element. Basically all form elements get rendered with the form_element theme theme_form_element($element,$value); (form.inc file)

So to change how this renders your form elements you simply copy that function to your template.php folder and rename it to: phptemplate_form_element($element,$value)

now you can make any changes and they will be used instead of the original function

  1. Copy theme_form_element($element,$value); from form.inc
  2. Paste it into (your theme) template.php
  3. rename it to: phptemplate_form_element($element,$value)
  4. clear all theme cache
  5. make whatever changes you want and they will be used.
0

Importantly, theme_form_element will only modify the direct parent wrapper div and this may not be the intended target for CSS effects.

[Although not programmatic, if one simply wants to apply a class to a node field's top-wrapper (it's wrapper's, wrapper's, wrapper) one can I suppose use "Field group" module by selecting "Manage Fields" for a particular content type and select "Add new group" as a simple DIV. Then the label can be removed and desired classes assigned to the additional wrapper (but now we have even more wrappers) - with unlimited nesting]

0

You could use

'#prefix' => '<div class="new_class">', '#suffix' => '</div>'

and this will wrap it around

0

Make wrapper attributes configurable!

Create your own form-element theme function in your theme... sites/all/themes/MY_THEME/theme/form-element.theme.inc

function my_theme_form_element($variables) {
  $element = &$variables['element'];

  $attributes = isset($element['#my_theme_wrapper_attributes']) ?
    $element['#my_theme_wrapper_attributes'] : array();

  ...

  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";

  ...
}

Then you can do stuff like this...

function my_module_form_alter(&$form, &$form_state, $form_id) {
  $form['account']['mail']['#my_theme_wrapper_attributes']['class'][] = 'form-field--inline';
}
0

There are come cases in which neither #prefix/#suffix nor #attributes => array('class') give the desired results. My particular case is adding a class to the ajax-wrapper div around a managed_file element. #prefix/#suffix creates a new container and #attributes/'class' modifies the class of an inner element, not the outermost.

The normal outermost div is just

<div id="edit-doc1--XX-ajax-wrapper">

which is difficult to target in CSS. I can target [id^="edit-doc"] or [id$="-ajax-wrapper"] but both of these target more than just the elements I wanted.

The solution I came up with is to add a #process element to the form and manually manipulate the element's code. Here's the #process attribute added to the form item's declaration:

$form['doc1'] = array(
  '#type' => 'managed_file',
  '#process' => array('mymodule_managed_file_process'),
);

And here's the mymodule_managed_file_process() function:

function mymodule_managed_file_process($element, &$form_state, $form) {

  // Call the original function to perform its processing.
  $element = file_managed_file_process($element, $form_state, $form);

  // Add our own class for theming.
  $element['#prefix'] = str_replace(
    'id=',
    'class="managed-file-wrapper" id=',
    $element['#prefix']
  );

  return $element;
}

Relying on string substitution isn't very portable, so use str_replace at your own risk. This code, however, does indeed alter the outermost DIV to add the necessary class:

<div class="managed-file-wrapper" id="edit-doc1--XX-ajax-wrapper">

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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