Skip to main content
bootstrap  form tabs

Creating horizontal form tabs in Drupal 7

Creating Vertical tabs in Drupal 7 forms is an easy task, but to accommodate the design needs we at times have to use different style. For instance, horizontal tab might be needed. The same makes more sense for shopping cart check out like pages. And here the need for looking solutions outside the Drupal core arises as horizontal tabs are not readily available in core.

But contrib modules come into play to unleash the confinements of Drupal core. I'm going to uncover a Drupal way of creating Horizontal tabs using Field Group contrib module in this blog post. Beware there is another contrib module with similar name and it is obsolete now. 

In a hushed way this module provides a new Form API type, essentially to use in tandem with Fields (a.k.a CCK). But there is no documentation or API reference to exhibit its usage to leverage the same with custom forms.

After a few code walkthrough & some trail-and-error effort I was able to figure its usage and it is very similar to vertical tabs in core.

Let's take the below code snippet from quiz.module,

if (function_exists('userpoints_userpointsapi') && variable_get('quiz_has_userpoints', 1)) {
  $form['userpoints'] = array(
    '#type' => 'fieldset',
    '#title' => t('Userpoints'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#group' => 'additional_settings',
  $form['userpoints']['has_userpoints'] = array(
    '#type' => 'checkbox',
    '#default_value' => (isset($node->has_userpoints) ? $node->has_userpoints : 1),
    '#title' => t('Enable UserPoints Module Integration'),
    '#description' => t('If checked, marks scored in this @quiz will be credited to userpoints. For each correct answer 1 point will be added to user\'s point.', array('@quiz' => QUIZ_NAME)),
  $form['userpoints']['userpoints_tid'] = array(
    '#type' => 'select',
    '#options' => _quiz_userpoints_type(),
    '#title' => t('Userpoints Category'),
    '#states' => array(
      'visible' => array(
        ':input[name=has_userpoints]' => array('checked' => TRUE),
    '#default_value' => isset($node->userpoints_tid) ? $node->userpoints_tid : 0,
    '#description' => t('Select the category to which user points to be added. To add new category see <a href="!url">admin/structure/taxonomy/userpoints</a>', array('!url' => url('admin/structure/taxonomy/userpoints'))),

This code should be quite self explanatory for any  Drupal developer., But still to brief, essentially we are defining a new fieldset in quiz node form if Userpoints module is enabled. The key-value '#group' => 'additional_settings' turns this fieldset into a vertical tab item.

This is how it looks in the node form,

Now to turn (CCK) fields in Drupal 7 to horizontal tabs style, we need to install the above mentioned Field groups module and create wrapper field types in needed content types. For instance see the snapshots below,

Manage fields page of Article content type

Field groups module has got adequate pointers to play with fields.

More snapshots of mange fields page can be found in project page under "Extra screenshots and video's" section.

The interesting spice of this module would be to add Horizontal tabs to custom forms, which could be achieved by using the new form api type "horizontal_tabs" which is defined in Field groups (but not properly documented).

See the code below to show case its usage,

$form = array();
$form['my_field'] = array(
  '#type' => 'horizontal_tabs',
  '#tree' => TRUE,
  '#prefix' => '<div id="unique-wrapper">',
  '#suffix' => '</div>',
$items = array(
    'nid' => 1,
    'name' => 'Item 1'
    'nid' => 2,
    'name' => 'Item 2'
    'nid' => 3,
    'name' => 'Item 3'
    'nid' => 4,
    'name' => 'Item 4'
$counter = 1;
foreach ($items as $item) {
  $nid = $item['nid'];
  $form['my_field']['stuff'][$nid] = array(
    '#type' => 'fieldset',
    '#title' => t('Item @no', array('@no' => $counter)),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  $form['my_field']['stuff'][$nid]['form']['item_id'] = array(
    '#type' => 'value',
    '#value' => $item['nid'],
  $form['my_field']['stuff'][$nid]['form']['item_name'] = array(
    '#type' => 'value',
    '#value' => $item['name'],
  $form['my_field']['stuff'][$nid]['form']['remove'] = array(
      '#type' => 'checkbox',
      '#title' => t('Remove this item'),
      '#weight' => -51,
  // more field definition
  $form['my_field']['stuff'][$nid]['form']['#tree'] = TRUE;
  $form['my_field']['stuff'][$nid]['form']['#parents'] = array('my_field', 'stuff', $nid, 'form');

The above code snippet tries to provide a practical example to leverage the handy form api type. The code should be self explanatory and can be extended by copy pasting the same in any form builder / form alter function.

The code would produce output as below,

Snapshot of Horizontal tab code snippet

Hope this will save the time of others.


Tommaso Barina (not verified)

Sat, 01/17/2015 - 08:52

Thanks for this post.
Please note that you forgot to mention that field_group's css and js files must be attached to the form like this:

$form['#attached']['css'] = array(
drupal_get_path('module', 'field_group') . '/horizontal-tabs/horizontal-tabs.css',
$form['#attached']['js'] = array(
drupal_get_path('module', 'field_group') . '/horizontal-tabs/horizontal-tabs.js',

Best regards.

SpartyDan (not verified)

Thu, 08/27/2015 - 14:47

If the words "Show" and "Hide" are appearing in your tabs you can change:

'#collapsible' => TRUE,
'#collapsed' => TRUE,


'#collapsible' => FALSE,
'#collapsed' => FALSE,

to remove them.