diff --git a/core/includes/common.inc b/core/includes/common.inc
index 91956d4..a3b91b6 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2800,7 +2800,7 @@ function drupal_get_library($module, $name = NULL) {
 }
 
 /**
- * Assists in adding the tableDrag JavaScript behavior to a themed table.
+ * Assists in attaching the tableDrag JavaScript behavior to a themed table.
  *
  * Draggable tables should be used wherever an outline or list of sortable items
  * needs to be arranged by an end-user. Draggable tables are very flexible and
@@ -2839,9 +2839,13 @@ function drupal_get_library($module, $name = NULL) {
  * - Rows with the 'tabledrag-leaf' class cannot have child rows.
  * - Rows with the 'tabledrag-root' class cannot be nested under a parent row.
  *
- * Calling drupal_add_tabledrag() would then be written as such:
+ * Calling drupal_attach_tabledrag() would then be written as such:
  * @code
- * drupal_add_tabledrag('my-module-table', 'order', 'sibling', 'my-elements-weight');
+ * drupal_attach_tabledrag('my-module-table', array(
+ *   'action' => 'order',
+ *   'relationship' => 'sibling',
+ *   'group' => 'my-elements-weight',
+ * );
  * @endcode
  *
  * In a more complex case where there are several groups in one column (such as
@@ -2851,13 +2855,19 @@ function drupal_get_library($module, $name = NULL) {
  * $form['my_elements'][$region][$delta]['weight']['#attributes']['class'] = array('my-elements-weight', 'my-elements-weight-' . $region);
  * @endcode
  *
- * $group is still 'my-element-weight', and the additional $subgroup variable
- * will be passed in as 'my-elements-weight-' . $region. This also means that
- * you'll need to call drupal_add_tabledrag() once for every region added.
+ * The 'group' option is still 'my-element-weight', and the additional
+ * 'subgroup' option will be passed in as 'my-elements-weight-' . $region. This
+ * also means that you'll need to call drupal_attach_tabledrag() once for every
+ * region added.
  *
  * @code
  * foreach ($regions as $region) {
- *   drupal_add_tabledrag('my-module-table', 'order', 'sibling', 'my-elements-weight', 'my-elements-weight-' . $region);
+ *   drupal_attach_tabledrag('my-module-table', array(
+ *     'action' => 'order',
+ *     'relationship' => sibling',
+ *     'group' => 'my-elements-weight',
+ *     'subgroup' => my-elements-weight-' . $region,
+ *   ));
  * }
  * @endcode
  *
@@ -2867,69 +2877,71 @@ function drupal_get_library($module, $name = NULL) {
  * theme_menu_overview_form() for an example creating a table containing parent
  * relationships.
  *
- * Note that this function should be called from the theme layer, such as in a
- * .html.twig file, theme_ function, or in a template_preprocess function, not
- * in a form declaration. Though the same JavaScript could be added to the page
- * using drupal_add_js() directly, this function helps keep template files
- * clean and readable. It also prevents tabledrag.js from being added twice
- * accidentally.
- *
- * @param $table_id
- *   String containing the target table's id attribute. If the table does not
- *   have an id, one will need to be set, such as <table id="my-module-table">.
- * @param $action
- *   String describing the action to be done on the form item. Either 'match'
- *   'depth', or 'order'. Match is typically used for parent relationships.
- *   Order is typically used to set weights on other form elements with the same
- *   group. Depth updates the target element with the current indentation.
- * @param $relationship
- *   String describing where the $action variable should be performed. Either
- *   'parent', 'sibling', 'group', or 'self'. Parent will only look for fields
- *   up the tree. Sibling will look for fields in the same group in rows above
- *   and below it. Self affects the dragged row itself. Group affects the
- *   dragged row, plus any children below it (the entire dragged group).
- * @param $group
- *   A class name applied on all related form elements for this action.
- * @param $subgroup
- *   (optional) If the group has several subgroups within it, this string should
- *   contain the class name identifying fields in the same subgroup.
- * @param $source
- *   (optional) If the $action is 'match', this string should contain the class
- *   name identifying what field will be used as the source value when matching
- *   the value in $subgroup.
- * @param $hidden
- *   (optional) The column containing the field elements may be entirely hidden
- *   from view dynamically when the JavaScript is loaded. Set to FALSE if the
- *   column should not be hidden.
- * @param $limit
- *   (optional) Limit the maximum amount of parenting in this table.
+ * @param $element
+ *   A form element to attach the tableDrag behavior to.
+ * @param array $options
+ *   These options are used to generate JavaScript settings necessary to
+ *   configure the tableDrag behavior appropriately for this particular table.
+ *   An associative array containing the following keys:
+ *   - 'table_id': String containing the target table's id attribute.
+ *     If the table does not have an id, one will need to be set,
+ *     such as <table id="my-module-table">.
+ *   - 'action': String describing the action to be done on the form item.
+ *      Either 'match' 'depth', or 'order':
+ *     - 'match' is typically used for parent relationships.
+ *     - 'order' is typically used to set weights on other form elements with
+ *       the same group.
+ *     - 'depth' updates the target element with the current indentation.
+ *   - 'relationship': String describing where the "action" option
+ *     should be performed. Either 'parent', 'sibling', 'group', or 'self':
+ *     - 'parent' will only look for fields up the tree.
+ *     - 'sibling' will look for fields in the same group in rows above and
+ *       below it.
+ *     - 'self' affects the dragged row itself.
+ *     - 'group' affects the dragged row, plus any children below it (the entire
+ *       dragged group).
+ *   - 'group': A class name applied on all related form elements for this action.
+ *   - 'subgroup': (optional) If the group has several subgroups within it, this
+ *     string should contain the class name identifying fields in the same
+ *     subgroup.
+ *   - 'source': (optional) If the $action is 'match', this string should contain
+ *     the classname identifying what field will be used as the source value
+ *     when matching the value in $subgroup.
+ *   - 'hidden': (optional) The column containing the field elements may be
+ *     entirely hidden from view dynamically when the JavaScript is loaded. Set
+ *     to FALSE if the column should not be hidden.
+ *   - 'limit': (optional) Limit the maximum amount of parenting in this table.
+ *
  * @see theme_menu_overview_form()
  */
-function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgroup = NULL, $source = NULL, $hidden = TRUE, $limit = 0) {
-  $js_added = &drupal_static(__FUNCTION__, FALSE);
-  $tabledrag_id = &drupal_static(__FUNCTION__  . '_setting', FALSE);
-  $tabledrag_id = (!isset($tabledrag_id)) ? 0 : $tabledrag_id + 1;
+function drupal_attach_tabledrag(&$element, array $options) {
+  // Add default values to elements.
+  $options = $options + array(
+    'subgroup' => NULL,
+    'source' => NULL,
+    'hidden' => TRUE,
+    'limit' => 0
+  );
 
-  if (!$js_added) {
-    // Add the table drag JavaScript to the page before the module JavaScript
-    // to ensure that table drag behaviors are registered before any module
-    // uses it.
-    drupal_add_library('system', 'drupal.tabledrag');
-    $js_added = TRUE;
-  }
+  $group = $options['group'];
+
+  $tabledrag_id = &drupal_static(__FUNCTION__, FALSE);
+  $tabledrag_id = (!isset($tabledrag_id)) ? 0 : $tabledrag_id + 1;
 
   // If a subgroup or source isn't set, assume it is the same as the group.
-  $target = isset($subgroup) ? $subgroup : $group;
-  $source = isset($source) ? $source : $target;
-  $settings['tableDrag'][$table_id][$group][$tabledrag_id] = array(
+  $target = isset($options['subgroup']) ? $options['subgroup'] : $group;
+  $source = isset($options['source']) ? $options['source'] : $target;
+  $settings['tableDrag'][$options['table_id']][$group][$tabledrag_id] = array(
     'target' => $target,
     'source' => $source,
-    'relationship' => $relationship,
-    'action' => $action,
-    'hidden' => $hidden,
-    'limit' => $limit,
+    'relationship' => $options['relationship'],
+    'action' => $options['action'],
+    'hidden' => $options['hidden'],
+    'limit' => $options['limit'],
   );
-  drupal_add_js($settings, 'setting');
+
+  $element['#attached']['library'][] = array('system', 'drupal.tabledrag');
+  $element['#attached']['js'][] = array('data' => $settings, 'type' => 'setting');
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index a83b7a5..9545be7 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1368,7 +1368,11 @@ function theme_image($variables) {
  *   '#header' => array(t('Title'), array('data' => t('Operations'), 'colspan' => '1')),
  *   // Optionally, to add tableDrag support:
  *   '#tabledrag' => array(
- *     array('order', 'sibling', 'thing-weight'),
+ *     array(
+ *       'action' => 'order',
+ *       'relationship' => 'sibling',
+ *       'group' => 'thing-weight',
+ *     ),
  *   ),
  * );
  * foreach ($things as $row => $thing) {
@@ -1402,14 +1406,14 @@ function theme_image($variables) {
  *
  * @param array $element
  *   A structured array containing two sub-levels of elements. Properties used:
- *   - #tabledrag: The value is a list of arrays that are passed to
- *     drupal_add_tabledrag(). The HTML ID of the table is prepended to each set
- *     of arguments.
+ *   - #tabledrag: The value is a list of $options arrays that are passed to
+ *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
+ *     $options array.
  *
  * @see system_element_info()
  * @see theme_table()
  * @see drupal_process_attached()
- * @see drupal_add_tabledrag()
+ * @see drupal_attach_tabledrag()
  */
 function drupal_pre_render_table(array $element) {
   foreach (element_children($element) as $first) {
@@ -1440,13 +1444,13 @@ function drupal_pre_render_table(array $element) {
   // Take over $element['#id'] as HTML ID attribute, if not already set.
   element_set_attributes($element, array('id'));
 
-  // If the custom #tabledrag is set and there is a HTML ID, inject the table's
-  // HTML ID as first callback argument and attach the behavior.
+  // If the custom #tabledrag is set and there is a HTML ID, add the table's
+  // HTML ID to the options and attach the behavior.
   if (!empty($element['#tabledrag']) && isset($element['#attributes']['id'])) {
-    foreach ($element['#tabledrag'] as &$args) {
-      array_unshift($args, $element['#attributes']['id']);
+    foreach ($element['#tabledrag'] as $options) {
+      $options['table_id'] = $element['#attributes']['id'];
+      drupal_attach_tabledrag($element, $options);
     }
-    $element['#attached']['drupal_add_tabledrag'] = $element['#tabledrag'];
   }
 
   return $element;
diff --git a/core/lib/Drupal/Core/Config/Entity/DraggableListController.php b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
index 5370be5..2cb3f43 100644
--- a/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
+++ b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
@@ -101,7 +101,11 @@ public function buildForm(array $form, array &$form_state) {
       '#header' => $this->buildHeader(),
       '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])),
       '#tabledrag' => array(
-        array('order', 'sibling', 'weight'),
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'weight',
+        ),
       ),
     );
 
diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js
index f8dc614..ae2dec0 100644
--- a/core/misc/tabledrag.js
+++ b/core/misc/tabledrag.js
@@ -11,9 +11,9 @@ var showWeight = JSON.parse(localStorage.getItem('Drupal.tableDrag.showWeight'))
 /**
  * Drag and drop table rows with field manipulation.
  *
- * Using the drupal_add_tabledrag() function, any table with weights or parent
- * relationships may be made into draggable tables. Columns containing a field
- * may optionally be hidden, providing a better user experience.
+ * Using the drupal_attach_tabledrag() function, any table with weights or
+ * parent relationships may be made into draggable tables. Columns containing a
+ * field may optionally be hidden, providing a better user experience.
  *
  * Created tableDrag instances may be modified with custom behaviors by
  * overriding the .onDrag, .onDrop, .row.onSwap, and .row.onIndent methods.
diff --git a/core/modules/block/lib/Drupal/block/BlockListController.php b/core/modules/block/lib/Drupal/block/BlockListController.php
index 9524b0d..6db9219 100644
--- a/core/modules/block/lib/Drupal/block/BlockListController.php
+++ b/core/modules/block/lib/Drupal/block/BlockListController.php
@@ -200,18 +200,17 @@ public function buildForm(array $form, array &$form_state) {
     // Loop over each region and build blocks.
     foreach ($block_regions_with_disabled as $region => $title) {
       $form['blocks']['#tabledrag'][] = array(
-        'match',
-        'sibling',
-        'block-region-select',
-        'block-region-' . $region,
-        NULL,
-        FALSE,
+        'action' => 'match',
+        'relationship' => 'sibling',
+        'group' => 'block-region-select',
+        'subgroup' => 'block-region-' . $region,
+        'hidden' => FALSE,
       );
       $form['blocks']['#tabledrag'][] = array(
-        'order',
-        'sibling',
-        'block-weight',
-        'block-weight-' . $region,
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'block-weight',
+        'subgroup' => 'block-weight-' . $region,
       );
 
       $form['blocks'][$region] = array(
diff --git a/core/modules/book/book.admin.inc b/core/modules/book/book.admin.inc
index 0ffefc5..f74c196 100644
--- a/core/modules/book/book.admin.inc
+++ b/core/modules/book/book.admin.inc
@@ -22,9 +22,6 @@
 function theme_book_admin_table($variables) {
   $form = $variables['form'];
 
-  drupal_add_tabledrag('book-outline', 'match', 'parent', 'book-plid', 'book-plid', 'book-mlid', TRUE, MENU_MAX_DEPTH - 2);
-  drupal_add_tabledrag('book-outline', 'order', 'sibling', 'book-weight');
-
   $header = array(t('Title'), t('Weight'), t('Parent'), t('Operations'));
 
   $rows = array();
@@ -77,6 +74,28 @@ function theme_book_admin_table($variables) {
     $row['class'][] = 'draggable';
     $rows[] = $row;
   }
-  $table = array('#theme' => 'table', '#header' => $header, '#rows' => $rows, '#attributes' => array('id' => 'book-outline'), '#empty' => t('No book content available.'));
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'book-outline'),
+    '#empty' => t('No book content available.'),
+    '#tabledrag' => array(
+      array(
+        'action' => 'match',
+        'relationship' => 'parent',
+        'group' => 'book-plid',
+        'subgroup' => 'book-plid',
+        'source' => 'book-mlid',
+        'hidden' => TRUE,
+        'limit' => MENU_MAX_DEPTH - 2,
+      ),
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'book-weight',
+      ),
+    ),
+  );
   return drupal_render($table);
 }
diff --git a/core/modules/field/field.form.inc b/core/modules/field/field.form.inc
index ebdc3d7..c7c2e05 100644
--- a/core/modules/field/field.form.inc
+++ b/core/modules/field/field.form.inc
@@ -70,21 +70,26 @@ function theme_field_multiple_value_form($variables) {
     }
 
     $table = array(
-      '#theme' => 'table',
+      '#type' => 'table',
       '#header' => $header,
       '#rows' => $rows,
       '#attributes' => array(
         'id' => $table_id,
         'class' => array('field-multiple-table'),
       ),
+      '#tabledrag' => array(
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => $order_class,
+        ),
+      ),
     );
     $output = '<div class="form-item">';
     $output .= drupal_render($table);
     $output .= $element['#description'] ? '<div class="description">' . $element['#description'] . '</div>' : '';
     $output .= '<div class="clearfix">' . drupal_render($add_more_button) . '</div>';
     $output .= '</div>';
-
-    drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
   }
   else {
     foreach (element_children($element) as $key) {
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
index a974937..0858119 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverviewBase.php
@@ -123,6 +123,20 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
       // Add Ajax wrapper.
       '#prefix' => '<div id="field-display-overview-wrapper">',
       '#suffix' => '</div>',
+      '#tabledrag' => array(
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'field-weight',
+        ),
+        array(
+          'action' => 'match',
+          'relationship' => 'parent',
+          'group' => 'field-parent',
+          'subgroup' => 'field-parent',
+          'source' => 'field-name',
+        ),
+      ),
     );
 
     // Field rows.
@@ -194,10 +208,6 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
 
     $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui');
 
-    // Add tabledrag behavior.
-    $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'order', 'sibling', 'field-weight');
-    $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name');
-
     return $form;
   }
 
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php
index aad6599..272d807 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php
@@ -136,7 +136,15 @@ public function getRegionOptions() {
    * This function is assigned as a #pre_render callback in
    * field_ui_element_info().
    *
-   * @see drupal_render().
+   * @param array $element
+   *   A structured array containing two sub-levels of elements. Properties
+   *   used:
+   *   - #tabledrag: The value is a list of $options arrays that are passed to
+   *     drupal_attach_tabledrag(). The HTML ID of the table is added to each
+   *     $options array.
+   *
+   * @see drupal_render()
+   * @see drupal_pre_render_table()
    */
   public function tablePreRender($elements) {
     $js_settings = array();
@@ -207,6 +215,16 @@ public function tablePreRender($elements) {
       'data' => array('fieldUIRowsData' => $js_settings),
     );
 
+    // If the custom #tabledrag is set and there is a HTML ID, add the table's
+    // HTML ID to the options and attach the behavior.
+    // @see drupal_pre_render_table()
+    if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
+      foreach ($elements['#tabledrag'] as $options) {
+        $options['table_id'] = $elements['#attributes']['id'];
+        drupal_attach_tabledrag($elements, $options);
+      }
+    }
+
     return $elements;
   }
 
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index de6350c..dee5b4e 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -413,15 +413,20 @@ function theme_file_widget_multiple($variables) {
     );
   }
 
-  drupal_add_tabledrag($table_id, 'order', 'sibling', $weight_class);
-
   $build = array(
-    '#theme' => 'table',
+    '#type' => 'table',
     '#header' => $headers,
     '#rows' => $rows,
     '#attributes' => array(
       'id' => $table_id,
     ),
+    '#tabledrag' => array(
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => $weight_class,
+      ),
+    ),
   );
 
   $output = empty($rows) ? '' : drupal_render($build);
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php b/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
index 5ca05c2..1529bab 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatFormControllerBase.php
@@ -137,7 +137,11 @@ public function form(array $form, array &$form_state) {
       '#attributes' => array('id' => 'filter-order'),
       '#title' => t('Filter processing order'),
       '#tabledrag' => array(
-        array('order', 'sibling', 'filter-order-weight'),
+        array(
+         'action' => 'order',
+         'relationship' => 'sibling',
+         'group' => 'filter-order-weight',
+        ),
       ),
       '#tree' => FALSE,
       '#input' => FALSE,
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index b8f9c96..1d13ba8 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -58,8 +58,14 @@ function theme_image_style_effects($variables) {
     '#header' => $header,
     '#rows' => $rows,
     '#attributes' => array('id' => 'image-style-effects'),
+    '#tabledrag' => array(
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'image-effect-order-weight',
+      ),
+    ),
   );
-  drupal_add_tabledrag('image-style-effects', 'order', 'sibling', 'image-effect-order-weight');
   return drupal_render($table);
 }
 
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index f9443c7..f02d7bd 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -214,17 +214,23 @@ function theme_language_negotiation_configure_form($variables) {
     }
 
     $build = array(
-      '#theme' => 'table',
+      '#type' => 'table',
       '#header' => $header,
       '#rows' => $rows,
       '#attributes' => array('id' => "language-negotiation-methods-$type"),
+      '#tabledrag' => array(
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => "language-method-weight-$type",
+        ),
+      ),
     );
+
     $table  = drupal_render($form[$type]['configurable']);
     $table .= drupal_render($build);
     $table .= drupal_render_children($form[$type]);
 
-    drupal_add_tabledrag("language-negotiation-methods-$type", 'order', 'sibling', "language-method-weight-$type");
-
     $output .= '<div class="form-item table-language-group table-' . $type . '-wrapper">' . $title . $description . $table . '</div>';
   }
 
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index 2fe9455..57bba6d 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -17,9 +17,6 @@
 function theme_menu_overview_form($variables) {
   $form = $variables['form'];
 
-  drupal_add_tabledrag('menu-overview', 'match', 'parent', 'menu-plid', 'menu-plid', 'menu-mlid', TRUE, MENU_MAX_DEPTH - 1);
-  drupal_add_tabledrag('menu-overview', 'order', 'sibling', 'menu-weight');
-
   $header = array(
     t('Menu link'),
     array('data' => t('Enabled'), 'class' => array('checkbox')),
@@ -62,12 +59,28 @@ function theme_menu_overview_form($variables) {
   }
 
   $table = array(
-    '#theme' => 'table',
+    '#type' => 'table',
     '#header' => $header,
     '#rows' => $rows,
     '#attributes' => array(
       'id' => 'menu-overview',
     ),
+    '#tabledrag' => array(
+      array(
+        'action' => 'match',
+        'relationship' => 'parent',
+        'group' => 'menu-plid',
+        'subgroup' => 'menu-plid',
+        'source' => 'menu-mlid',
+        'hidden' => TRUE,
+        'limit' => MENU_MAX_DEPTH - 1,
+      ),
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'menu-weight',
+      ),
+    ),
   );
 
   $output .= drupal_render($form['inline_actions']);
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Form/SetCustomize.php b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetCustomize.php
index ac9c37d..80e9a01 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Form/SetCustomize.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Form/SetCustomize.php
@@ -58,7 +58,11 @@ public function form(array $form, array &$form_state) {
       '#empty' => $this->t('No shortcuts available. <a href="@link">Add a shortcut</a>', array('@link' => $this->urlGenerator()->generateFromRoute('shortcut.link_add', array('shortcut_set' => $this->entity->id())))),
       '#attributes' => array('id' => 'shortcuts'),
       '#tabledrag' => array(
-        array('order', 'sibling', 'shortcut-weight'),
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'shortcut-weight',
+        ),
       ),
     );
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 859b2a1..1c1929a 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -585,10 +585,10 @@ function system_element_info() {
     '#process' => array('form_process_table'),
     '#element_validate' => array('form_validate_table'),
     // Properties for tabledrag support.
-    // The value is a list of arrays that are passed to drupal_add_tabledrag().
-    // drupal_pre_render_table() prepends the HTML ID of the table to each set
-    // of arguments.
-    // @see drupal_add_tabledrag()
+    // The value is a list of arrays that are passed to
+    // drupal_attach_tabledrag(). drupal_pre_render_table() prepends the HTML ID
+    // of the table to each set of options.
+    // @see drupal_attach_tabledrag()
     '#tabledrag' => array(),
     // Render properties.
     '#pre_render' => array('drupal_pre_render_table'),
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
index 25edaad..9bd534d 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Form/OverviewTerms.php
@@ -307,20 +307,18 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
 
     if ($parent_fields) {
       $form['terms']['#tabledrag'][] = array(
-        'match',
-        'parent',
-        'term-parent',
-        'term-parent',
-        'term-id',
-        FALSE,
+        'action' => 'match',
+        'relationship' => 'parent',
+        'group' => 'term-parent',
+        'subgroup' => 'term-parent',
+        'source' => 'term-id',
+        'hidden' => FALSE,
       );
       $form['terms']['#tabledrag'][] = array(
-        'depth',
-        'group',
-        'term-depth',
-        NULL,
-        NULL,
-        FALSE
+        'action' => 'depth',
+        'relationship' => 'group',
+        'group' => 'term-depth',
+        'hidden' => FALSE,
       );
       $form['terms']['#attached']['library'][] = array('taxonomy', 'drupal.taxonomy');
       $form['terms']['#attached']['js'][] = array(
@@ -328,7 +326,11 @@ public function buildForm(array $form, array &$form_state, VocabularyInterface $
         'type' => 'setting',
       );
     }
-    $form['terms']['#tabledrag'][] = array('order', 'sibling', 'term-weight');
+    $form['terms']['#tabledrag'][] = array(
+      'action' => 'order',
+      'relationship' => 'sibling',
+      'group' => 'term-weight',
+    );
 
     if ($taxonomy_vocabulary->hierarchy != TAXONOMY_HIERARCHY_MULTIPLE && count($tree) > 1) {
       $form['actions'] = array('#type' => 'actions', '#tree' => FALSE);
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
index dff2c6f..850885a 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/Rearrange.php
@@ -77,7 +77,11 @@ public function buildForm(array $form, array &$form_state) {
       '#header' => array('', $this->t('Weight'), $this->t('Remove')),
       '#empty' => $this->t('No fields available.'),
       '#tabledrag' => array(
-        array('order', 'sibling', 'weight'),
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'weight',
+        )
       ),
       '#tree' => TRUE,
       '#prefix' => '<div class="scroll" data-drupal-views-scroll>',
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
index 1bdf851..82d796c 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ReorderDisplays.php
@@ -60,7 +60,11 @@ public function buildForm(array $form, array &$form_state) {
       '#header' => array($this->t('Display'), $this->t('Weight'), $this->t('Remove')),
       '#empty' => $this->t('No displays available.'),
       '#tabledrag' => array(
-        array('order', 'sibling', 'weight'),
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'weight',
+        )
       ),
       '#tree' => TRUE,
       '#prefix' => '<div class="scroll" data-drupal-views-scroll>',
diff --git a/core/modules/views_ui/views_ui.theme.inc b/core/modules/views_ui/views_ui.theme.inc
index a13467e..ae32eaf 100644
--- a/core/modules/views_ui/views_ui.theme.inc
+++ b/core/modules/views_ui/views_ui.theme.inc
@@ -206,8 +206,14 @@ function theme_views_ui_build_group_filter_form($variables) {
       'class' => array('views-filter-groups'),
       'id' => 'views-filter-groups',
     ),
+    '#tabledrag' => array(
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'weight',
+      )
+    ),
   );
-  drupal_add_tabledrag('views-filter-groups', 'order', 'sibling', 'weight');
   $render_form = drupal_render_children($form);
   return $output . $render_form . drupal_render($table) . drupal_render($form['add_group']) . $more;
 }
@@ -226,7 +232,14 @@ function theme_views_ui_rearrange_filter_form(&$variables) {
     if ($group_id !== 'ungroupable') {
       // Set up tabledrag so that it changes the group dropdown when rows are
       // dragged between groups.
-      drupal_add_tabledrag('views-rearrange-filters', 'match', 'sibling', 'views-group-select', 'views-group-select-' . $group_id);
+      $options = array(
+        'table_id' => 'views-rearrange-filters',
+        'action' => 'match',
+        'relationship' => 'sibling',
+        'group' => 'views-group-select',
+        'subgroup' => 'views-group-select-' . $group_id,
+      );
+      drupal_attach_tabledrag($form['override'], $options);
 
       // Title row, spanning all columns.
       $row = array();
@@ -286,7 +299,6 @@ function theme_views_ui_rearrange_filter_form(&$variables) {
   }
 
   if (!empty($ungroupable_rows)) {
-    drupal_add_tabledrag('views-rearrange-filters-ungroupable', 'order', 'sibling', 'weight');
     $header = array(t('Ungroupable filters'), t('Weight'), array('class' => array('views-hide-label'), 'data' => t('Group')), array('class' => array('views-hide-label'), 'data' => t('Remove')));
     $table = array(
       '#theme' => 'table',
@@ -296,12 +308,18 @@ function theme_views_ui_rearrange_filter_form(&$variables) {
         'id' => 'views-rearrange-filters-ungroupable',
         'class' => array('arrange'),
       ),
+      '#tabledrag' => array(
+        array(
+          'action' => 'order',
+          'relationship' => 'sibling',
+          'group' => 'weight',
+        )
+      ),
     );
     $output .= drupal_render($table);
   }
 
   // Set up tabledrag so that the weights are changed when rows are dragged.
-  drupal_add_tabledrag('views-rearrange-filters', 'order', 'sibling', 'weight');
   $table = array(
     '#theme' => 'table',
     '#rows' => $rows,
@@ -309,6 +327,13 @@ function theme_views_ui_rearrange_filter_form(&$variables) {
       'id' => 'views-rearrange-filters',
       'class' => array('arrange'),
     ),
+    '#tabledrag' => array(
+      array(
+        'action' => 'order',
+        'relationship' => 'sibling',
+        'group' => 'weight',
+      )
+    ),
   );
   $output .= drupal_render($table);
   $output .= '</div>';
