I have formatted my field sets in a form builder function to display as vertical tabs. Here's a snippet of my code. It works fine:

$form['vertical_tabs'] = array(
    '#type' => 'vertical_tabs',

// * Form elements: fieldset tree.
$form['episode'] = array(
    '#title' => t('Episode details'),
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#collapsible' => TRUE,
    '#group' => 'vertical_tabs',

I see a lot of vertical tabs with, let's call it, a menu subtitle just below the menu title. It's the grey text under the blue anchor text in this pic from the vertical_tabs module page - the top one reads 'Create new revision':

enter image description here

I guessed, wrongly, that adding a #description attribute with my menu subtitle would add it in, but is just appears at the top the field sets' tab contents. Does anyone know how this is done?



Some may consider this not to be the 'correct' Drupal way, but this is simple, requires hardly any code, resides in the Sites folder (so it won't be over written on update), and does not require editing any core files. Just a bit of CSS. This is what I did:

.vertical-tabs ul.vertical-tabs-list li:nth-child(1) .summary:after {
  content: 'Menu subtitle 1';
.vertical-tabs ul.vertical-tabs-list li:nth-child(2) .summary:after {
  content: 'Menu subtitle 2';

Clive's answer (see below) may be a better option if you're handy with JavaScipt.


Here, is a jQuery solution I've developed:

Add this jQuery file to your module directory, call it jquery.YOURFILE.js:

 * Vertical tabs summary setters.
(function( $ ) {
  $(function() {
    $( ".summary:gt(0)" ).html( "Foo" );
    $( ".summary:gt(2)" ).html( "Bar" );
})( jQuery );

Here I used the .gt method, but you could target tabs individually with the .eq method. In your form element definition, where you define your fieldsets, add:

'#attached' => array(
  'js' => array(drupal_get_path('module', 'YOURMODULE') . '/jquery.YOURFILE.js'),


See the vertical_tabs examples module for another way to do this.

Look in content_types.inc and content_types.js in the node module too.

This is an update of the jQuery file above. It uses Drupal.behaviors and the eq method. Probably more 'correct' than the one above.

(function ($) {

Drupal.behaviors.yourModule = {
  attach: function (context) {
    $( ".summary:eq(0)" ).html( "Foo" );
    $( ".summary:eq(1)" ).html( "Bar" );
    $( ".summary:eq(2)" ).html( "Baz" );

  • 2
    Click here for drupal documentation on vertical tabs.
    – Jayaram
    Commented Apr 4, 2013 at 21:53

1 Answer 1


The tab summary is set by JavaScript (I don't think you can do it in PHP), per the comments in misc/vertical-tabs.js:

Each tab may have a summary which can be updated by another script. For that to work, each fieldset has an associated 'verticalTabCallback' (with jQuery.data() attached to the fieldset), which is called every time the user performs an update to a form element inside the tab pane.

The node module has a good example of how to do this, the code in node.js should be pretty easy to adapt for your own module:

Drupal.behaviors.nodeFieldsetSummaries = {
  attach: function (context) {
    $('fieldset.node-form-revision-information', context).drupalSetSummary(function (context) {
      var revisionCheckbox = $('.form-item-revision input', context);

      // Return 'New revision' if the 'Create new revision' checkbox is checked,
      // or if the checkbox doesn't exist, but the revision log does. For users
      // without the "Administer content" permission the checkbox won't appear,
      // but the revision log will if the content type is set to auto-revision.
      if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $('.form-item-log textarea', context).length)) {
        return Drupal.t('New revision');

      return Drupal.t('No revision');


I think the only PHP change you'll need to make is to add a specific class to the fieldset so the JS can target it:

$form['episode'] = array(
  '#title' => t('Episode details'),
  '#type' => 'fieldset',
  '#tree' => TRUE,
  '#collapsible' => TRUE,
  '#group' => 'vertical_tabs',
  '#attributes' => array('class' => array('mymodule-node-options')),
  • Thanks - but there are HTML tags already present with a class. After the title it goes: <span class="summary"></span>. So I guess I just need the js in my module.
    – dbj44
    Commented Apr 4, 2013 at 21:16
  • You might not consider this the right Drupal way, but I could do: .summary:after { content: 'Subtitle text';}. As long as I target each tab individually.
    – dbj44
    Commented Apr 4, 2013 at 21:50
  • 1
    Nah when you get to JS it's every man for himself, the Drupal way can take a back seat to what's quickest IMO ;)
    – Clive
    Commented Apr 4, 2013 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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