I wrote this as I felt that the instructions for theming webforms was a little vague and confusing. It might just have been me, but maybe this will help someone else - I can't be the only confused person out there....can I? :) So here goes....

We can use theming to add CSS id's and classes to webforms. There are two methods available, each have their own advantages.

Method 1

can create new fieldsets easily without re-doing the webform
can add any html code you before and after the fieldsets
two files to edit

Add the following code to your template.php file to redirect processing to your own template file:

//change the number here '123' to the id number of your webform
function phptemplate_webform_form_123 ($form) {
  return _phptemplate_callback('webform_form_123', array('form' => $form));

Then create the file you mentioned in the callback statement above. In this case its called webform_form_123.tpl.php. Now you can create fieldsets and add your own CSS id's or classes to them, using the prefix and suffix attributes to add a new div (you can put anything you want here):

$form['submitted']['fluentin'] = array(
	'#type' => 'fieldset',
	'#prefix' => '<div id="vol-fluentin">',
	'#suffix' => '</div>',
	'#weight' => -1,

$form['submitted']['otherlang'] = array(
	'#type' => 'fieldset',
	'#prefix' => '<div id="vol-otherlang">',
	'#suffix' => '</div>',
	'#weight' => 0,

// Move the form field labeled "whatever" to the new fieldset
// $form['submitted']['newfieldset']['whatever'] = $form['submitted']['whatever'];

$form['submitted']['fluentin']['Fluent in'] = $form['submitted']['Fluent in'];
unset($form['submitted']['Fluent in']);
$form['submitted']['otherlang']['Please specify other languages'] = $form['submitted']['Please specify other languages'];
unset($form['submitted']['Please specify other languages']);

echo form_render($form);

The important thing here is to remember to unset the original form field, otherwise it will appear twice - once within the new fieldset and once in its original position. By creating the new div's you can then style these form item specifically.

The new version of webform now has the ability to creat fieldsets and place form items within them. However, there is no option to add an id or class to these fieldsets. Hence the above technique.

Method 2

single file to edit
simple coding to change form item attributes eg #id
can't create new fieldsets or add html code before or after

I recently discovered another way to add a CSS id to a specific form item using only template.php. This technique only modifies form items that already exist and does not create new fieldsets etc. So, add the following code to template.php:

function phptemplate_webform_form_50 ($form) {
  $form['submitted']['First Name']['#id'] = 'edit-submitted-first-name';
  $form['submitted']['Last Name']['#id'] = 'edit-submitted-last-name';
  $form['submitted']['Fluent in']['#id'] = 'edit-submitted-fluency';
  return _phptemplate_callback('webform_form_50', array('form' => $form));

This code changes the #id attribute to the text specified after the = sign, for whichever form item you want.

NOTE! When you are using the above two methods make sure that you escape any apostrophe's that appear in the field's name.

For example, you create a checkbox field called Bureau d'inscription. Using either method, the bit before the equals sign should be written as follows:

$form['submitted']['Bureau d\'inscription']....

Take note of the backslash within the name. If you don't do it, you're statement becomes invalid and doesn't execute. At worst it could invalidate all proceeding statements too.

Well, I hope someone finds this useful - otherwise I just wasted the last 30 minutes typing instead of sleeping :) Actually, it wasn't a total waste for me - its helped me organize my methods to theme webforms. And that escaping apostrophe thing is gold for those of us who create french webforms.


jasonwhat’s picture

Cool little tutorial. How about theming node forms? One of my problems has been that they are so difficult to theme because the fields all have standard div tags so if you change it one node add form, you change it for all.

stanbroughl’s picture

yes i was trying to figure that out yesterday - just simple things would be great like inlining checkboxes so they don't take up half the page would be great.

Anyone have any suggestions/solutions?

ckeo’s picture

any themable function... you can copy and paste into your template.php file (change name from theme_something to phptemplate_something) and then you can rearrange things. (thats how i themed my forums.... tho comments are not done yet).

you can also ( cant remember the link at the moment, but i know its in here someplace. ) use a different node template depending on the typeof node.

by the way incrn8: thats awesome... i actually learned somethings from your explanation and i never consider posting such things a waste of time.


incrn8’s picture


After doing the theming, I could finally target specific form-items. I have attached a screenshot that shows a form I am currently using (click here). In the screenshot you can see regular text fields eg. website, that have the input positioned to the right of the label.

The method I used (there are many others) was to position:relative the form-item, then I could absolute position the input within that. However, for the Coach input, I wanted the title to appear after the coach input, so absolute positioning would not have worked, hence I reset its positioning to the default, static. Then I floated the .form-item div within #schl-coach div (this div was added using theming Method 1). For the language checkboxes, I did the same thing.

Note that I found that I had to use the node id to get the more general styles to work. There is obviously some CSS heirarchy in there somewhere, so be aware of that. Anyway, by using the node id, it allows you to target that specific form.

Here is the CSS to position the various elements:

#node-103 .form-item {position:relative}
#node-103 label {display:inline}
#node-103 input {position:absolute;left:13em}

#schl-coach input {position:static}
#schl-lang .form-item, #schl-coach .form-item {float:left;padding-right:3em}
#schl-lang input {position:static;margin-right:5px}
#schl-lang .description {clear:both}

Hope this helps.


incrn8’s picture

I assume you are talking about the forms used to create a new node eg. page, etc. I have not needed to do that, so I can't help you directly. However, theming should work the same way as for webforms (which are just fancy nodes). The tricky bit would be figuring out the name of the node so that you can create the template file eg. story would be story.tpl.php, I think. Then to CSS style specific nodes, you would include the node ID in the style definition (see comments below for help).


quineto’s picture


I am trying to theme the email that webform sends but i can not use any design with HTML just plain text.

Have u tried to send the webform email with html code? please let me know if you guys have done something like this

When I either print it with PHP or embed it with the PHP code it comes out the HTML code and not the design, I guess that it may be a problem of the X-Mailer and comes out the bare code:

any ideas please?

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html> <head>    <title>Requisicion de Personal</title>    <meta http-equiv="Content-Style-Type" content="text/css" /> <style type="text/css"> <!--    .style2 {font-size: 24px}       -->     </style>  </head><body><table width="581" border="1">  <tr>    <td colspan="2"><div align="center" class="style2">Requisicion de Personal</div></td>  </tr>  <tr>    <td width="250" bgcolor="#339999"><div align="right">Fecha de Env&iacute;o: </div></td>    <td width="315" bgcolor="#339999">2006-10-07 00:12</td>  </tr>  <tr>    <td bgcolor="#339999"><div align="right">De la maquina con IP</div></td>    <td bgcolor="#339999"></td>  </tr>  <tr>    <td colspan="2"><hr></td>  </tr></table><table width="580" border="1">  <tr>    <td width="233">Unidad de negocio solicitante:</td>    <td width="171"> SCALMAC Huichihuayán, S.L.P.</td>  </tr>  <tr>    <td>&nbsp;</td>    <td>&nbsp;</td>  </tr></table><p>&nbsp;</p></body></html>
incrn8’s picture

Sorry, but I haven't done that myself, so I can't offer any suggestions. However, I think you may be right about the email headers being the problem. You might have to put something like the following into the headers somehow:

 Content-Type:multipart/mixed; boundary=message;
 My Message.

I don't how to get it into the header section, though. You might have to create a new module with a form_alter function. Sorry I can't be of more help.

Recent Drupal websites: http://mbacasecomp.com and http://hudsonhistoricalsociety.ca


quineto’s picture

I change the send mail function under the user.module, which I think is the one that sends the emails at the end, there I added Content-Type:text/html but it doesn´t seem to take in the email format.

I don´t know actually where to start since I see that there are 3 levels one for the core system, the webform module and the xmailer add on.

rigth now I am looking in the webform module but haven´t being succesful yet

i opened a issue report in case you want to follow this



quicksketch’s picture

incrn8, great tutorial!

Webform has been using the title of components as the key in webforms for a long time, which has been the cause of much grief. The apostrophe issue you mentioned kind of cured itself with 4.7 releases, then broke again with 4.7.2/.3. Either way, we knew it was a bad idea to keep using the component title as the name for the form field.

In recent changes we started using the component identifier instead, which is just a number. So instead of:

$form['submitted']['Bureau d\'inscription']

You'll have something like:


Which ugly but it saves us a lot of grief when posting/processing forms. Thanks again for the great reference.

Nathan Haug
creative graphic design        w: quicksketch.org
& software development       e: nate@quicksketch.org

goose2000’s picture

I notice that for each form component, there is a description field.
When you view the form, this description text is under/below the form element.
So, it is a bit out of place I would think.

Is there a way to move this to the top?


BioALIEN’s picture

Thank incrn8, this should be moved to the documentation page of the webform module. At the moment there is a lack of documentation for this module.
iScene Interactive :: iScene.eu

Valdes@www.drupalitalia.org’s picture

I have searched extensively the site but I didn't find an answer to my questions, which are:

how can I have a webform output that shows, for example, the lfield NAME and the field SECOND NAME on the same line/row instead of one per line ? And how can I insert an image between form lines/rows ? (follows a kind of graphical example of what I mean)

Oppss, my poor english and my poorer knowledge of programming (let's say it's about 0) prevented me from grasping that the above posts answer the question I have made. Pardon me.

chrizz’s picture

Hi Valdes,

You can insert an image by selecting a markup component and then just use HTML to refer to the image.

I also desperatly need some information about placing fields in the same row. Ideas somebody?

cratos’s picture

I'm also trying this, with no success...

I've found some tutorials teaching how to theme the email. But i still havent found how to customize the end form...

Can anyone help, or redirect me to a tutorial??



kumarldh’s picture

Hey cratos
You need to do some CSS stuff, here is what you can do,
a) remove margins/set margins to 0 on labels and fields
b) set width of labels and float them to left
and see the result
Here is my CSS

/*Contact form*/
border:1px dotted #f00;

.form-item input.error, .form-item textarea.error {
border: 1px solid #c52020;
color: #494949;


#webform-client-form-1 label{
width: 30%;
float: left;

.webform-component-textfield, .webform-component-select, .webform-component-email{

#webform-component-name input,
#webform-component-bedrijf input,
#webform-component-afdeling input,
#webform-component-adres input,
#webform-component-adres2 input,
#webform-component-email input,
#webform-component-tel input{
border:#102d2b 1px solid;
#webform-component-bericht textarea{
border:#102d2b solid 1px;

font-family:verdana, arial, helvetica;
font-size: 14px;
padding:3px 25px 3px 25px;

The only issue I am facing now is the resize class messing up the text area.


Why is drupal so hard to learn?

cratos’s picture

Thanks for the help kumarldh.

I will try it in the weekend.

Just one question. The CSS coding goes to the file "style.css" in the active theme, right?

Thanks a lot.


kumarldh’s picture

The CSS goes into style.css, you can link your own CSS too, but use style.css, and if you are good at CSS, you will never need to follow any of the ways mentioned here. I themed the form using CSS only. :)

Another way is to load the webform node, hack down the array and use what ever you wish to do, pretty basic but more control on the look and feel, here is one I did, *not recommended*

function myWebform($w){
 $t = '<form action="'.base_path().'en/contact"  accept-charset="UTF-8" method="post" id="webform-client-form-'.$w['nid'].'" enctype="multipart/form-data">
 hello world
  <table border="0" cellpadding="0" cellspacing="0" class="form-table">

// for($i=1;$i<=count($w['components']);$i++)
 foreach($w['components'] as $c){
   $t .='     <tr align="left" valign="top">
     <td class="form-item">'.($c['name']=='Adres2'?'&nbsp;':$c['name']).( $c['mandatory']==1?'<span class="form-required" title="This field is required.">*</span>':'').'</td>
     <td class="form-field-item">'.(($c['type']=='textfield' || $c['type']=='email')?
     '<input type="text" name="submitted['.$c['name'].']" id="edit-submitted-'.$c['name'].'"  size="60" value="" class="form-text" />':
     '<textarea rows="" name="submitted['.$c['form_key'].']" id="edit-submitted-'.$c['form_key'].'"  class="form-textarea resizable"></textarea>').'</td>
 $t .= '     <tr align="left" valign="top">
     <td class="form-item">Ik heb interesse in</td>
  <tr align="left" valign="top">
     <td class="form-item">&nbsp;</td>
     <td style="border-top:1px solid #1b443e;padding-top:2px">
     <input type="hidden" name="details[email_subject]" id="edit-details-email-subject" value="default"  />
<input type="hidden" name="details[email_from_name]" id="edit-details-email-from-name" value=""  />
<input type="hidden" name="details[email_from_address]" id="edit-details-email-from-address" value=""  />
<input type="hidden" name="form_id" id="edit-webform-client-form-'.$w['nid'].'" value="webform_client_form_'.$w['nid'].'"  />
<input type="submit" name="op" id="edit-submitbutton" value="Send"  class="form-submit" />&nbsp;<input type="reset" name="op" id="edit-resetbutton" value="Clear"  class="form-reset" /></td>
 return ($t);	
function myNodeTheme($n){
  $arrayNode = array();
    case 'page':
      $arrayNode['title'] = $n->title;
      $arrayNode['body'] = $n->body;
      $arrayNode['headerimage'] = $node->field_headerimage;
    case 'webform':
      $arrayNode['title'] = $n->title;
      $node = node_load($n->nid);
      $arrayNode['body'] = myWebform($n->webform);
      $arrayNode['headerimage'] = $node->field_headerimage;

put this in template.php and voila :D
dont tell me the above code is horrible, I already know :P

Why is drupal so hard to learn?

flavor’s picture


Your examples are great I have a few questions...

How to you deal with grid layouts, only on grid layouts in fieldsets do I need to have the .form-item label on the top, this is because having it on the left breaks the layout.

J -

http://www.ridgeworksinc.com - helping you participate in the Internet!

Parkes Design’s picture

kumarldh you are the man. I was able to style form elements using CSS. Its pretty fiddly but it gave me the outcome I wanted which was radio buttons and check boxes side by side!

kumarldh’s picture

form_render is deprecated in D5, use drupal_render and both the methods failed in D6, I am really annoyed.

Why is drupal so hard to learn?

billybob4’s picture

Interesting stuff.

Your examples show how to add fieldsets and set prefix and suffix etc.

What I want to do is to override the standard prefix and suffix of each form field to get rid of all the divs, classes, and ids etc. Is there a way to do this?

e.g. I want to change the standard field prefix from something like this:

<div class="webform-component-textfield" id="webform-component-name">
<div class="form-item">

to this:




Aha. As simple as:

$form['submitted']['name']['#prefix'] = "<li>";

I've also have found that you can add your own class to the input items with the following:

$form['submitted']['name']['#attributes']['class'] = "your_class_name";

Might be useful to someone

amanda’s picture

Where are you putting

$form['submitted']['name']['#prefix'] = "

  • ";
  • bmango’s picture

    Nice examples, thanks incrn8 (i used the css way, a lot simpler than the php code...)

    tomsm’s picture

    I arranged the components by adding css rules to my local.css file.
    By combining the id of the form + id of the component it is very easy to specify the component you want to theme.

    OhSnapNo’s picture

    Make sure you check out the arrange fields module.

    kardave’s picture

    To add css class or classes to a webform element:
    $form['submitted']['First Name']['#attributes']['class'] = array('my-class', 'my-other-class');

    You can do it even in webform-form.tpl.php if you copy it to your templates folder.

    I wanted to add a class to all select element. This worked for me:

    foreach ($form['submitted'] as $key => $value) {
    	if(isset($value['#webform_component']['type']) && $value['#webform_component']['type'] == 'select'){
    		$form['submitted'][$key]['#attributes']['class'] = array('styled');
    webcultist’s picture

    Following code in your template.php

    function THEMENAME_form_alter(&$form, &$form_state, $form_id) {
      switch ($form_id) {
        case 'webform_client_form_2149':
          $form['#attributes']['class'][] = 'sample-order-form';