Last updated June 12, 2012. Created on December 21, 2005.
Edited by HongPong, add1sun, Steve Dondley, sepeck. Log in to edit this page.

This tip will show you how to modify the checkboxes element type so that checkboxes display in multiple columns instead of one single column. This is particularly useful for modules that would have users select from a very long list of choices. This tip will help you present the checkboxes in a more compact form, making your site more user friendly.

See also the Multi-column checkboxes radios module for a Drupal 6 solution with Drupal 7 currently in development.

Disclaimer: This document shares how I solved this particular problem and doesn't claim to be anything more. There may be other ways of accomplishing the same thing. If you are a forms API guru and know an easier way, please share!

The first job is to override the expand_element_checkboxes() function in the form.inc. Here's how it looks:

<?php
function expand_checkboxes($element) {
 
$value = is_array($element['#value']) ? $element['#value'] : array();
 
$element['#tree'] = TRUE;
  if (
count($element['#options']) > 0) {
    if (!isset(
$element['#default_value']) || $element['#default_value'] == 0) {
     
$element['#default_value'] = array();
    }
    foreach (
$element['#options'] as $key => $choice) {
      if (!isset(
$element[$key])) {
       
$element[$key] = array('#type' => 'checkbox', '#processed' => TRUE, '#title' => $choice, '#default_value' => in_array($key, $value), '#attributes' => $element['#attributes']);
      }
    }
  }
  return
$element;
}
?>

To override it, the first step is to actually put the new function in our module. Here it is:

<?php
function expand_checkbox_columns($element) {
 
$value = is_array($element['#value']) ? $element['#value'] : array();
 
$element['#type'] = 'checkboxes';
 
$element['#tree'] = TRUE;
  if (
count($element['#options']) > 0) {
    if (!isset(
$element['#default_value']) || $element['#default_value'] == 0) {
     
$element['#default_value'] = array();
    }
    foreach (
$element['#options'] as $key => $choice) {
     
$class = ($column % $element['#columns']) && $column ? 'checkbox-columns' : 'checkbox-columns-clear';
      if (!isset(
$element[$key])) {
       
$element[$key] = array('#type' => 'checkbox', '#processed' => TRUE, '#title' => $choice, '#default_value' => in_array($key, $value), '#attributes' => $element['#attributes'], '#prefix' => '<div class="' . $class . '">', '#suffix' => '</div>');
      }
     
$column++;
    }
  }
  return
$element;
}
?>

The above function contains the logic that will create our multi-column list of checkboxes. Notice it is the same as the expand_checkboxes_function except it has a different name, "expand_checkbox_columns", and it has some code that puts some div tags in front of the checkboxes. The div tags are how we ultimately control which column the checkboxes appear. Also notice this line:

<?php
$element
['#type'] = 'checkboxes';
?>

That line is in there to suppress a bug in the current version of forms api. In the interests of brevity, I'll skip over exactly why that's there. But basically, all it does is fool forms.inc that all it's dealing with is your standard checkboxes element type.

The next step is to let Drupal know about the new "expand_checkbox_columns" function you just created. You do that by putting a hook_elements function in your module like so:

<?php
function yourmodulename_elements() {
 
$type['checkbox_columns'] = array('#input' => TRUE, '#process' => array('expand_checkbox_columns' => array()), '#tree' => TRUE);
  return
$type;
}
?>

Simple enough. But see the other tip about creating your own elements for more details on what exactly this does.

Next, of course, we need some code that actually puts our new element function to use. Here's an example:

<?php
  $form
['example_of_multicolumn_checkbox_element'] = array(
   
'#type' => 'checkbox_columns',
   
'#title' => t('Check off which kinds of politicians you\'d like to track'),
   
'#default_value' => $value,
   
'#columns' => 3,
   
'#options' => array('foo' => 'Label 1', 'bar' => 'Label 2', 'baz' => 'Label 3'),
   
'#suffix' => '<br style="clear:both;"/>',
  );
?>

Couple of things to point out here. First the '#type' is set to 'checkbox_columns'. This is how we ensure our new expand_checkbox_columns function gets called. Second, notice the "#columns' property. This is how you can change the number of columns displayed. If you look at the new expand_checkbox_columns() function we created above, you'll see that it makes use of the '#columns' value.

Our last step is to add some CSS to our style sheet so this will work. Here's how:

.checkbox-columns .form-item {
  width: 15em;
  margin-right: 10px;
  float: left;
  display: inline;
}

.checkbox-columns-clear .form-item {
  width: 15em;
  margin-right: 10px;
  clear: left;
  float: left;
  display: inline;
}

And that should do it. Notice that you can control the width of the columns by changing the width property (set to 15em). You will want to change this according to the length of your longest checkbox selection to give your list a nice neat appearance.

For a discussion and examples for how to get taxonomy term selectors turned into checkboxes check out this thread Select Taxonomy terms as checkboxes and radio buttons.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

NancyDru’s picture

I accomplish this by adding a div (using #prefix and #suffix), and then pure CSS from there.

  $form['field1'] = array('#type' => 'checkboxes',
    ...
    '#prefix' => '<div class="my_checkboxes">',
    '#suffix' => '</div>');

Then in the CSS:

.my_checkboxes .form-item label.option {
  float: left;
  width: 20%;
}

.my_checkboxes .form-item .description {
  clear: both;
}

Instead of a fixed width, you can also just do "margin-right: 2em;"

This technique also works quite well with radios too.

NancyDru (formerly Nancy W. until I got married to Drupal)

ngstigator’s picture

Neat Jedi CSS trick!

Thanks you saved me from theme_views_filter() surgery. I only wished I'd found this thread sooner :-)

cside’s picture

Hi
Have used the code in example 1 and want to use this in a specific content type that i have created. I know that the $elements hook must refer to something other than function yourmodulename_elements() but being a complete novice at coding, i have no idea what exactly i should replace yourmodulename with.

Can someone please put me out of my misery?

Thanks

echaland’s picture

I tried the CSS, and it worked great. Thanks! Now, if I use CCK to create checkboxes fields what field should I specified in $form['field'] to add the #prefix and #suffix...
Thanks

NancyDru’s picture

Firebug is a neat little add-on to the Firefox browser. With it you can look at any single element of a page and discover it's attributes, including the divs that it is in. It makes figuring these things out easy.

NancyDru

Rob T’s picture

Where exactly does the first part of NancyDru's solution get applied?

Am I creating a new module? Is this a template.php override?

NancyDru’s picture

It gets applied to the forms code in the module.

NancyDru (formerly Nancy W. until I got married to Drupal)

docans’s picture

plaease i would like to know to which file in the drupal installation to i apply the prefix and suffix i.e:

$form['field1'] = array('#type' => 'checkboxes',
...
'#prefix' => '',
'#suffix' => '');

. Which file do i paste it into

robmil29’s picture

I did this easily with jquery

$("div[id^='edit-field-industry']").css("float","left");
$("div[id^='edit-field-industry']").css("width","30%");
wfx’s picture

myregistration’s picture

if($('.group-fieldname').length)
{
    $(".group-fieldname .form-checkboxes").find('div.form-item').css("float","left");
    $(".group-fieldname .form-checkboxes").find('div.form-item').css("width","30%");
    $(".group-fieldname label").css("clear","both");
}