ctools Modals and Vertical Tabs

The Chaos tool suite (ctools) is collection of useful methods intended to help Drupal developers create complex interfaces without duplicating too much effort.

Drupal 7 introduced a new Form API element: Vertical Tabs. When you set a parent element as this Form API type, then any child elements that are of type fieldset are displayed as vertical tabs instead of as in the traditional fieldset. Unfortunately for us developers, the documentation does not provide an example of how to use Vertical Tabs properly, but with some trial and error you can do it.

However, this new Vertical Tab Form API element doesn’t work in modal multistep wizard forms created with ctools. If you look at the theme_vertical_tabs() method, you will notice it loads a Javascript library to do its magic.

This library won’t be loaded properly in a modal dialog. Instead you need to call that same drupal_add_library() method in your ctools form.

function blah_form($js, $step) {
  drupal_add_library('system', 'drupal.vertical-tabs');  
  // Other stuff...  The ctools_ajax_example module is a decent example of this part. 

and then you can use vertical tabs in your other form callbacks!

function blah_step1($form, &$form_state) {
  $form['blah'] = array(
    '#type' => 'vertical_tabs',
    '#tree' => TRUE,
  for ($i = 0; $i < 10; $i++) {
    $form['blah'][$i] = array(
      '#type' => 'fieldset',
      '#title' => t('Blah !n', array('!n' => $i),
      '#group' => 'blah',
      '#tree' => TRUE,
    $form['blah'][$i]['blahblah'] = array(
      '#type' => 'radios',
      '#title' => t('Blah Blah?'),
      '#options' => array(0 => t('No'), 1 => t('Yes'), 2 => t('Maybe')),
      '#default_value' => 0, 
  return $form;

Update 1/4/2012: This method is incomplete for Internet Explorer. Internet Explorer does not allow you to inject CSS into the DOM directly. This can be averted by using the addImport method, which only Internet Explorer supports. This is addressed in Lazy-loading CSS fails in IE issue on drupal.org so hopefully you will not need to do the following for much longer in the future.

    if (document.styleSheets[0].addImport) {
      document.styleSheets[0].addImport(' . DRUPAL_ROOT . '/misc/vertical_tabs.css);
  ', 'inline');

Matthew Radcliffe is a Drupal developer at Kosada, Inc. and contributor to the Drupal project including Drupal core, contributed projects, development environments and the Contribution Mentoring program among other things.