Skip to main content

Creating a form with draggable elements

25th December, 2014

In this blog post we give a step by step tutorial on creating forms with draggable elements.

Sometimes within the Drupal environment when working with the Form API it’s desirable to have control over the order of the output of elements. Historically Drupal handled this ordering with a weighting system, which basically meant that a user selected a number from a dropdown list (from -10 to 10) for each form element and this ‘weighting’ then determined where in the stack that particular item would be displayed. It’s worth noting that Drupal still uses this method, but since Drupal 6 functions have been available that add a layer of javascript to this functionality that literally gives the user the ability to ‘drag’ items into an order they’re happy with.

squiddy form

Today we’re going to look at a function called ‘drupal_add_tabledrag’. As it’s name somewhat suggests, it gives the user the ability to drag rows up and down within a table. If we render a form  wrapped in a table with this functionality, this immediately becomes useful - infact, we used drupal_add_tabledrag recently for a module (see fig 1) in which we wanted the user to be able to drag elements of a Tweet round into the order they wished them to be displayed on the front-end.

Fig 1

For this tutorial, we’ll be creating a new module that outputs a block with a form and the order of the elements within this form will be draggable.

First off, create a folder within ‘sites/default/modules’ (if the folder ‘modules’ doesn’t exist create it) called ‘curve_table_drag’ and inside this folder create 2 files - named ‘’ and ‘curve_table_drag.module’. Open up ‘’ and paste the following code into the file:

name = Curve Table Drag
description = This module demonstrates table drag functionality within Drupal.
core = 7.x
package = Curve Agency

All we’re basically doing here is defining basic information about this module. With the creation of those two files and the inclusion of module information in the *.info file, we’ve basically just defined all that’s required for us to turn the module on and begin writing module code (even though admittedly the module doesn’t actually currently do anything). When done navigate to ‘admin/modules’ within your Drupal install and switch the newly created module module on.

The first thing we’re going to add to ‘curve_table_drag.module’  is an instance of hook_form() which defines a parent form element and 5 child items (all of which contain a label and two text fields - one of which is used for the weighting). Let’s paste the following code into our *.module file.

Implementation of hook_form()
 * Implements hook_form().
function curve_table_drag_form($form, &$form_state) {
  $form['curve_table_drag_attributes'] = array(
    '#prefix' => '<div id="curve-attributes">',
    '#suffix' => '</div>',
    '#tree' => TRUE,
    '#theme' => 'curve_table_drag_components',
  for($i=1; $i<6; $i++) {
    $form['curve_table_drag_attributes'][$i]['label'] = array(
      '#type' => 'item',
      '#markup' => "Item" . $i,
    $form['curve_table_drag_attributes'][$i]['textfield'] = array(
      '#type' => 'textfield', 
      '#default_value' => 'Sample textfield ' . $i,
      '#size' => 60, 
      '#maxlength' => 128, 
      '#required' => TRUE,
    $form['curve_table_drag_attributes'][$i]['weight'] = array(
      '#type' => 'textfield',
      '#default_value' => $i,
      '#size' => 3,
      '#attributes' => array('class' => array('item-row-weight')),
  return system_settings_form( $form );

One thing to note here is the addition of

'#attributes' => array('class' => array('item-row-weight'))

in the weight textfield. This is responsible for adding a class to this textfield that tells the ‘drupal_add_tabledrag’ function that this element defines the weight. Aside from this, we’re basically just taking advantage of functionality provided by Drupal in the form API (!topics!

Let’s now create the block that we will use to contain the form. Here we’ll be using both ‘hook_block_info()’ and ‘hook_block_view()’. Let’s paste the following two blocks of code into our module.

Implementation of hook_block_info()
 * Implements hook_block_info().
function curve_table_drag_block_info() {
  $blocks = array();
  $blocks['curve_table_drag_block'] = array(
    'info' => t('Block: Curve Table Drag'),
    'cache' => DRUPAL_NO_CACHE,
  return $blocks;
Implementation of hook_block_view()
 * Implements hook_block_view().
function curve_table_drag_block_view($block_name = '', $args = array()) {
  $block = '';
  switch ($block_name) {
    case 'curve_table_drag_block':
      $block['subject'] = t('Draggable table demo');
      $block['content'] = drupal_get_form('curve_table_drag_form');
  return $block;

Here we’re using ‘hook_block_info()’ to define the basic attributes of the block (i.e. the name of the block and the level of caching we want to have on this block). With ‘hook_block_view()’ we’re now saying to Drupal - hey, if you have a block defined as ‘curve_table_drag_block’ give it the title of ‘Draggable table demo’ and display the form we defined at the top of the module as it’s content. 

Let’s see what we’ve created so far looks like (you might need to clear your Drupal cache at this point by navigating to ‘admin/config/development/performance’ and selecting ‘Clear all caches’). Let’s navigate to ‘admin/structure/block’ and move ‘Block: Curve Table Drag’ into the content region (see fig 2).

Fig 2

Once saved, navigate to the homepage of your site and you should see something similar to the following (see fig 3).

Fig 3

This is good, but now let’s add the table drag functionality! For us to enable table drag functionality, we’re first going to define a theme implementation using ‘hook_theme()’ and we’re then going to build a theme function (that will be responsible for theming our form). First up, paste the following code into your *.module file.

Theme definition
 * Implements hook_theme().
function curve_table_drag_theme($existing, $type, $theme, $path) {
  $themes = array(
    'curve_table_drag_components' => array(
      'render element' => 'element'
  return $themes;

Here we’re essentially defining ‘theme_curve_table_drag_components’, which is included below. Paste the function ‘theme_curve_table_drag_components()’ into your module.

Custom theme template
// Custom theme output.
function theme_curve_table_drag_components($vars) {
  $element = $vars['element'];
  drupal_add_tabledrag('sample_table', 'order', 'sibling', 'item-row-weight');
  $header = array(
    'label' => t('Attribute'), 
    'checkbox' => t('Enabled/disabled'),
    'weight' => t('Weight'),
  $rows = array();
  foreach (element_children($element) as $key) {
    $row = array();
    $row['data'] = array();
    foreach ($header as $fieldname => $title) {
      $row['data'][] = drupal_render($element[$key][$fieldname]);
      $row['class'] = array('draggable');
    $rows[] = $row;
  return theme('table', array(
    'header' => $header, 
    'rows' => $rows,
    'attributes' => array('id' => 'sample_table'),

In a nutshell, this theme function takes the form array we defined right at the start of this tutorial and runs through it line by line, adds the class ‘draggable’ to each row and then outputs the whole form through a table with an ID of ‘sample_table’. Right at the top of this function we are calling ‘drupal_add_tabledrag()’ using the various classes we’ve defined throughout the the tutorial and if we’ve done everything correctly, your block displaying on the homepage should now look like this (see fig 4).

Fig 4

You now have a draggable list of form elements that can be ordered as you wish!

If you have any questions regarding the above, please feel free to get in touch with the Curve team here:

Drupal resources:!topics!forms_api_reference.html/7

If you have any questions regarding the above, please feel free to get in touch with the Curve team ( or Craig directly (

Pete McClory
Managing Director

Pete is the MD at Curve, helping with creative direction, business development and strategy. Also find him on , Twitter, and LinkedIn.