Last updated 9 August 2013. Created on 10 July 2013.
Edited by angel.h, Cyberwolf, pfrenssen. Log in to edit this page.

This is the documentation of the Paddle Admin Theme, the administration theme of the Paddle distribution, an initiative of the Flemish government.

This is intended for developers that are creating apps and additional functionality to use with the Paddle distribution, to ensure consistent theming.

Modal dialogs

The Paddle Admin Theme uses a modified version of the modals provided by CTools. We are using an overridden version of CTools' modal.js which can be found in our javascript/ folder.

The modal dialog is styled consistently throughout the administration section, and adapts itself automatically to the size of the contents and browser window. If the contents of the dialog are too large to fit in the window, a scrollbar appears, but the submit buttons remain visible at the bottom of the dialog.

Here is an example implementation of a modal dialog, taken from the Paddle Menu Manager module.

Create a menu item

CTools introduces the concept of an ajax command. A command is a javascript function within the Drupal.CTools.AJAX.commands namespace, which can be invoked as an ajax response.
The server-side callback returns an object representation of a command, and this object contains everything necessary to run the command on the client-side. The easiest way to explain this is with an example.

The first thing that is needed is a hook_menu() implementation to define a new path for the ajax callback.
Take note of the %ctools_js in the path. This is how we will determine if the call is being made from an ajax call or not. More on that when we get to the callback code.

 * Implements hook_menu().
function paddle_menu_manager_menu() {
  $items = array();

  $items['admin/structure/menu_manager/%ctools_js/add'] = array(
    'title' => 'Create new menu',
    'page arguments' => array(3),
    'page callback' => 'paddle_menu_manager_modal_menu_form',
    'access arguments' => array('manage paddle_menu_manager'),
    'type' => MENU_CALLBACK,

  return $items;

Page callback

The page callback checks if javascript is enabled. If it is not, it will return a regular form (generated by paddle_menu_manager_menu_form() in this example). If javascript is enabled, it will output the necessary CTools ajax commands that will open the modal.

 * Displays the menu form, in a modal dialog if supported.
 * @param bool $js
 *   Whether or not the page was called via javascript.
 * @param object $menu
 *   The menu item to edit, or NULL to add a new one.
 * @return array
 *   Returns a render array in case a modal dialog is not supported.
 *   Otherwise renders the necessary ajax commands itself and exits.
function paddle_menu_manager_modal_menu_form($js, $menu = NULL) {
  // Degrade to no js.
  if (!$js) {
    return drupal_get_form('paddle_menu_manager_menu_form', $menu);
  else {

    $form_state = array(
      'ajax' => TRUE,
      'build_info' => array(
        'args' => array(

    $output = ctools_modal_form_wrapper('paddle_menu_manager_menu_form', $form_state);

    if ($form_state['executed']) {
      $output = array();
      $output[] = ctools_modal_command_dismiss();
      $output[] = ctools_ajax_command_reload();

    print ajax_render($output);

Launching the modal

The modal can be launched by clicking on a specially formatted link or button on the page. There are two methods:

  1. Use ctools_modal_text_button() which adds the necessary ctools css classes automatically and has parameters for button text, page call back and css classes.
    This particular type of button consists of an extra span with a class 'visuallyhidden' to hide part of the label which indicates the action of the button for screen readers.
    ctools_modal_text_button() renders text as a link. This will automatically apply an AJAX class to the link and add the appropriate javascript to make this happen.
    See full documentation for ctools_modal_text_button().
      $output = ctools_modal_text_button(t('<span class="visuallyhidden">Create</span> Menu'), 'admin/structure/menu_manager/nojs/add', t('Create a new menu.'), 'ctools-modal-overlay-persist');
  2. Or you can have links and buttons bound to use the modal by adding the class ctools-use-modal.
      $form['ajax_button'] = array(
        '#type' => 'button',
        '#value' => t('A modal button'),
        '#attributes' => array(
          'class' => array(
        '#id' => 'ajax-button',

Structure of the modal content

Use these containers to wrap the content and the buttons in separate divs. This is needed to achieve the scrolling of the forms and have the buttons stick to the bottom.

 * Menu builder for the menu edit/create form.
function paddle_menu_manager_menu_form($form, &$form_state, $menu = NULL) {

  // Add containers around the form fields and submit buttons so that the
  // content can scroll, while the submit buttons stay in place.
  $form['body'] = array(
    '#type' => 'container',
    '#attributes' => array('class' => array('form-body')),
  $form['buttons'] = array(
    '#type' => 'container',
    '#attributes' => array('class' => array('form-buttons')),

  $form['body']['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Title'),

  $form['body']['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Description'),

  $form['buttons']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),

  return $form;

Different variants of the modal

We currently have two variants of the modal available: a default (570px wide) and a wider modal (870px).
To use the wider modal there is need to add an extra class to the ctools modal button: ctools-modal-wide-modal.

Ctools modals with a persistent overlay

For modules like the menu manager and the taxonomy manager we add an additional class to the ctools modal buttons: ctools-modal-overlay-persist. It will cause the overlay of the modal to remain after the dialog itself is removed. This is recommended when the page is going to be refreshed and we want to prevent the user from clicking in the page while this is happening.

paddle_themer_dialog.png5.74 KB

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