diff --git a/includes/nodequeue.admin.inc b/includes/nodequeue.admin.inc
index 3e71241..02d9403 100644
--- a/includes/nodequeue.admin.inc
+++ b/includes/nodequeue.admin.inc
@@ -696,7 +696,7 @@ function nodequeue_arrange_subqueue($queue, $subqueue = NULL) {
   // get nodes from the queue
   $nodes = _nodequeue_dragdrop_get_nodes($queue, $subqueue);
 
-  return drupal_get_form('nodequeue_arrange_subqueue_form', $queue, $nodes, $subqueue);
+  return drupal_get_form('nodequeue_arrange_subqueue_form_' . $subqueue->sqid, $queue, $nodes, $subqueue);
 }
 
 /**
@@ -791,6 +791,7 @@ function nodequeue_arrange_subqueue_form($form, $form_state, $queue, $nodes, $su
     '#autocomplete_path' => 'nodequeue/autocomplete/' . $subqueue->sqid,
     '#maxlength' => 1024,
     '#default_value' => t('Enter the title of a node to add it to the queue'),
+    '#attributes' => array('class' => array('subqueue-add-nid')),
   );
   $form['add']['submit'] = array(
     '#type' => 'submit',
@@ -802,7 +803,8 @@ function nodequeue_arrange_subqueue_form($form, $form_state, $queue, $nodes, $su
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
-    '#value' => t('Save')
+    '#value' => t('Save'),
+    '#submit' => array('nodequeue_arrange_subqueue_form_submit'),
   );
   $form['actions']['reverse'] = array(
     '#type' => 'submit',
diff --git a/nodequeue.module b/nodequeue.module
index 82a8df3..025b5f8 100644
--- a/nodequeue.module
+++ b/nodequeue.module
@@ -249,6 +249,19 @@ function nodequeue_node_view($node, $view_mode) {
 }
 
 /**
+ * Implementats hook_forms().
+ */
+function nodequeue_forms($form_id) {
+  $forms = array();
+  if (strpos($form_id, 'nodequeue_arrange_subqueue_form_') === 0) {
+    $forms[$form_id] = array(
+      'callback' => 'nodequeue_arrange_subqueue_form',
+    );
+  }
+  return $forms;
+}
+
+/**
  * Implements hook_theme().
  */
 function nodequeue_theme() {
@@ -2077,18 +2090,24 @@ function theme_nodequeue_arrange_subqueue_form_table($variables) {
 
   $output = '';
 
-  // get css to hide some of the help text if javascript is disabled
+  // Get css to hide some of the help text if javascript is disabled.
   drupal_add_css(drupal_get_path('module', 'nodequeue') . '/nodequeue.css');
 
-  // TODO: Would be nice to expose qid, sqid, reference as classes for more custom theming :).
-  // TODO: Create unique ID to make multiple tabledrag forms on a page possible
-  drupal_add_tabledrag('nodequeue-dragdrop', 'order', 'sibling', 'node-position');
+  $table_id = 'nodequeue-dragdrop-' . $form['#subqueue']['sqid'];
+  $table_classes = array(
+    'nodequeue-dragdrop',
+    'nodequeue-dragdrop-qid-' . $form['#subqueue']['qid'],
+    'nodequeue-dragdrop-sqid-' . $form['#subqueue']['sqid'],
+    'nodequeue-dragdrop-reference-' . $form['#subqueue']['reference'],
+  );
+  drupal_add_tabledrag($table_id, 'order', 'sibling', 'node-position');
   drupal_add_js(drupal_get_path('module', 'nodequeue') . '/nodequeue_dragdrop.js');
 
+  $reverse[str_replace('-', '_', $table_id)] = (bool) $form['#queue']['reverse'];
   drupal_add_js(
     array(
       'nodequeue' => array(
-        'reverse' => (bool) $form['#queue']['reverse'],
+        'reverse' => $reverse,
       )
     ),
     array(
@@ -2097,7 +2116,7 @@ function theme_nodequeue_arrange_subqueue_form_table($variables) {
     )
   );
 
-  // render form as table rows
+  // Render form as table rows.
   $rows = array();
   $counter = 1;
   foreach (element_children($form) as $key) {
@@ -2127,9 +2146,9 @@ function theme_nodequeue_arrange_subqueue_form_table($variables) {
     $rows[] = array(array('data' => t('No nodes in this queue.'), 'colspan' => 7));
   }
 
-  // render the main nodequeue table
+  // Render the main nodequeue table.
   $header = array(t('Title'), t('Author'), t('Post Date'), t('Position'), array('data' => t('Operations'), 'colspan' => 2), t('Position'));
-  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => array('nodequeue-dragdrop'), 'class' => array('nodequeue-dragdrop'))));
+  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => $table_id, 'class' => $table_classes)));
 
   return $output;
 }
diff --git a/nodequeue_dragdrop.js b/nodequeue_dragdrop.js
index 514fd05..c2e9fba 100644
--- a/nodequeue_dragdrop.js
+++ b/nodequeue_dragdrop.js
@@ -2,29 +2,35 @@
 
 Drupal.behaviors.nodequeueDrag = {
   attach: function(context) {
-    var tableDrag = Drupal.tableDrag['nodequeue-dragdrop'];
+    $('.nodequeue-dragdrop').each(function() {
+      var table_id = $(this).attr('id');
+      var tableDrag = Drupal.tableDrag[table_id];
 
-    tableDrag.onDrop = function() {
-      $('td.position').each(function(i){
-        $(this).html(i + 1);
-      });
+      tableDrag.onDrop = function() {
+        $('#' + table_id + ' td.position').each(function(i) {
+          $(this).html(i + 1);
+        });
 
-      nodequeueUpdateNodePositions();
-    }
+        nodequeueUpdateNodePositions(table_id);
+      }
+    });
   }
 };
 
 Drupal.behaviors.nodequeueReverse = {
   attach: function(context) {
-    $('#edit-reverse').click(function(){
-      // reverse table rows...
-      $('tr.draggable').each(function(i){
-        $('.nodequeue-dragdrop tbody').prepend(this);
+    $('#edit-actions-reverse').click(function() {
+      var $table = $(this).parent().parent().find('.nodequeue-dragdrop:first');
+      var table_id = $table.attr('id');
+
+      // Reverse table rows.
+      $table.find('tr.draggable').each(function(i) {
+        $table.find('tbody').prepend(this);
       });
 
-      nodequeueUpdateNodePositions();
-      nodequeueInsertChangedWarning();
-      nodequeueRestripeTable();
+      nodequeueUpdateNodePositions(table_id);
+      nodequeueInsertChangedWarning(table_id);
+      nodequeueRestripeTable(table_id);
 
       return false;
     });
@@ -33,17 +39,20 @@ Drupal.behaviors.nodequeueReverse = {
 
 Drupal.behaviors.nodequeueShuffle = {
   attach: function(context) {
-    $('#edit-shuffle').click(function(){
-      // randomize table rows...
-      var rows = $('table.nodequeue-dragdrop tbody tr:not(:hidden)').get();
+    $('#edit-actions-shuffle').click(function() {
+      var $table = $(this).parent().parent().find('.nodequeue-dragdrop:first');
+      var table_id = $table.attr('id');
+
+      // Randomize table rows.
+      var rows = $('#' + table_id + ' tbody tr:not(:hidden)').get();
       rows.sort(function(){return (Math.round(Math.random())-0.5);});
       $.each(rows, function(i, row) {
-        $('.nodequeue-dragdrop tbody').prepend(this);
+        $('#' + table_id + ' tbody').prepend(this);
       });
 
-      nodequeueUpdateNodePositions();
-      nodequeueInsertChangedWarning();
-      nodequeueRestripeTable();
+      nodequeueUpdateNodePositions(table_id);
+      nodequeueInsertChangedWarning(table_id);
+      nodequeueRestripeTable(table_id);
 
       return false;
     });
@@ -52,17 +61,20 @@ Drupal.behaviors.nodequeueShuffle = {
 
 Drupal.behaviors.nodequeueClear = {
   attach: function(context) {
-    $('#edit-clear').click(function(){
-      // mark nodes for removal
-      $('.node-position').each(function(i){
+    $('#edit-actions-clear').click(function() {
+      var $table = $(this).parent().parent().find('.nodequeue-dragdrop:first');
+      var table_id = $table.attr('id');
+
+      // Mark nodes for removal.
+      $('#' + table_id + ' .node-position').each(function(i) {
         $(this).val('r');
       });
 
-      // remove table rows...
-      rows = $('table.nodequeue-dragdrop tbody tr:not(:hidden)').hide();
+      // Remove table rows.
+      rows = $('#' + table_id + ' tbody tr:not(:hidden)').hide();
 
-      nodequeuePrependEmptyMessage();
-      nodequeueInsertChangedWarning();
+      nodequeuePrependEmptyMessage(table_id);
+      nodequeueInsertChangedWarning(table_id);
 
       return false;
     });
@@ -77,14 +89,17 @@ Drupal.behaviors.nodequeueRemoveNode = {
       a = '#' + a.replace('nodequeue-remove-', 'edit-') + '-position';
       $(a).val('r');
 
-      // hide the current row
-      $(this).parent().parent().fadeOut('fast', function(){
-        if ($('table.nodequeue-dragdrop tbody tr:not(:hidden)').size() == 0) {
-          nodequeuePrependEmptyMessage();
+      // Hide the current row.
+      $(this).parent().parent().fadeOut('fast', function() {
+        var $table = $(this).parent().parent();
+        var table_id = $table.attr('id');
+
+        if ($('#' + table_id + ' tbody tr:not(:hidden)').size() == 0) {
+          nodequeuePrependEmptyMessage(table_id);
         }
         else {
-          nodequeueRestripeTable()
-          nodequeueInsertChangedWarning();
+          nodequeueRestripeTable(table_id)
+          nodequeueInsertChangedWarning(table_id);
         }
       });
 
@@ -95,12 +110,12 @@ Drupal.behaviors.nodequeueRemoveNode = {
 
 Drupal.behaviors.nodequeueClearTitle = {
   attach: function(context) {
-    $('#edit-add-nid').focus(function() {
+    $('.subqueue-add-nid').focus(function() {
       if (this.value == this.defaultValue) {
         this.value = '';
         $(this).css('color', '#000');
       }
-    }).blur(function(){
+    }).blur(function() {
       if (!this.value.length) {
         this.value = this.defaultValue;
         $(this).css('color', '#999');
@@ -113,12 +128,12 @@ Drupal.behaviors.nodequeueClearTitle = {
  * Updates node positions after nodequeue has been rearranged.
  * It cares about the reverse order and populates nodes the other way round.
  */
-function nodequeueUpdateNodePositions() {
+function nodequeueUpdateNodePositions(table_id) {
   // Check if reverse option is set.
-  var reverse = Drupal.settings.nodequeue.reverse;
-  var size = reverse ? $('.node-position').size() : 1;
+  var reverse = Drupal.settings.nodequeue.reverse[table_id.replace(/-/g, '_')];
+  var size = reverse ? $('#' + table_id + ' .node-position').size() : 1;
 
-  $('.node-position').each(function(i){
+  $('#' + table_id + ' .node-position').each(function(i){
     $(this).val(size);
     reverse ? size-- : size++;
   });
@@ -128,8 +143,8 @@ function nodequeueUpdateNodePositions() {
  * Restripe the nodequeue table after removing an element or changing the
  * order of the elements.
  */
-function nodequeueRestripeTable() {
-  $('table.nodequeue-dragdrop tbody tr:not(:hidden)')
+function nodequeueRestripeTable(table_id) {
+  $('#' + table_id + ' tbody tr:not(:hidden)')
   .filter(':odd')
     .removeClass('odd').addClass('even')
       .end()
@@ -137,7 +152,7 @@ function nodequeueRestripeTable() {
     .removeClass('even').addClass('odd')
       .end();
 
-  $('tr:visible td.position').each(function(i){
+  $('#' + table_id + ' tr:visible td.position').each(function(i) {
     $(this).html(i + 1);
   });
 }
@@ -145,17 +160,17 @@ function nodequeueRestripeTable() {
 /**
  * Add a row to the nodequeue table explaining that the queue is empty.
  */
-function nodequeuePrependEmptyMessage() {
-  $('.nodequeue-dragdrop tbody').prepend('<tr class="odd"><td colspan="6">'+Drupal.t('No nodes in this queue.')+'</td></tr>');
+function nodequeuePrependEmptyMessage(table_id) {
+  $('#' + table_id + ' tbody').prepend('<tr class="odd"><td colspan="6">'+Drupal.t('No nodes in this queue.')+'</td></tr>');
 }
 
 /**
  * Display a warning reminding the user to save the nodequeue.
  */
-function nodequeueInsertChangedWarning() {
-  if (Drupal.tableDrag['nodequeue-dragdrop'].changed == false) {
-    $(Drupal.theme('tableDragChangedWarning')).insertAfter('.nodequeue-dragdrop').hide().fadeIn('slow');
-    Drupal.tableDrag['nodequeue-dragdrop'].changed = true;
+function nodequeueInsertChangedWarning(table_id) {
+  if (Drupal.tableDrag[table_id].changed == false) {
+    $(Drupal.theme('tableDragChangedWarning')).insertAfter('#' + table_id).hide().fadeIn('slow');
+    Drupal.tableDrag[table_id].changed = true;
   }
 }
 
