diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index cb7a84d..616370e 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1707,6 +1707,49 @@ function theme_links($variables) {
 }
 
 /**
+ * Builds a render array for theme_dropbutton().
+ */
+function template_preprocess_dropbutton(&$variables) {
+  $variables['attributes']['class'][] = 'dropbutton';
+  $variables['element'] = array(
+    '#theme' => 'links',
+    '#links' => $variables['links'],
+    '#attributes' => $variables['attributes'],
+    '#attached' => array(
+      'library' => array(
+        array('system', 'drupal.dropbutton'),
+      ),
+    ),
+  );
+  if (!empty($variables['links'])) {
+    $variables['element']['#prefix'] = '<div class="dropbutton-wrapper"><div class="dropbutton-widget">';
+    $variables['element']['#suffix'] = '</div></div>';
+  }
+  // Pass through title to the dropbutton options.
+  if (isset($variables['title'])) {
+    $variables['element']['#attached']['js'][] = array(
+      'type' => 'setting',
+      'data' => array('dropbutton' => array('title' => $variables['title'])),
+    );
+  }
+}
+
+/**
+ * Creates a dropbutton menu.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - title: (optional) The text placed in the clickable area to activate the
+ *     dropbutton. Defaults to 'Open dropbutton'.
+ *   - links: An array of links to provide in the dropbutton.
+ *   - attributes: (optional) An associative array of HTML attributes to apply
+ *     to the dropbutton.
+ */
+function theme_dropbutton($variables) {
+  return render($variables['element']);
+}
+
+/**
  * Returns HTML for an image.
  *
  * @param $variables
@@ -2904,6 +2947,9 @@ function drupal_common_theme() {
     'links' => array(
       'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
     ),
+    'dropbutton' => array(
+      'variables' => array('title' => NULL, 'links' => array(), 'attributes' => array()),
+    ),
     'image' => array(
       // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
       // allows the alt attribute to be omitted in some cases. Therefore,
diff --git a/core/misc/dropbutton/dropbutton.base-rtl.css b/core/misc/dropbutton/dropbutton.base-rtl.css
new file mode 100644
index 0000000..be6fd6c
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.base-rtl.css
@@ -0,0 +1,23 @@
+
+/**
+ * @file
+ * Base RTL styles for dropbuttons.
+ */
+
+/**
+ * The dropbutton arrow.
+ */
+.dropbutton-link {
+  left: 0;
+  right: auto;
+}
+.dropbutton-arrow {
+  left: 0.6667em;
+  right: auto;
+}
+.dropbutton-multiple .dropbutton-widget {
+  left: auto;
+  padding-left: 2em;
+  padding-right: 0;
+  right: 0;
+}
diff --git a/core/misc/dropbutton/dropbutton.base.css b/core/misc/dropbutton/dropbutton.base.css
new file mode 100644
index 0000000..1c05997
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.base.css
@@ -0,0 +1,99 @@
+
+/**
+ * @file
+ * Base styles for dropbuttons.
+ */
+
+/**
+ * When a dropbutton has only one option, it is simply a button.
+ */
+.dropbutton-wrapper,
+.dropbutton-wrapper div {
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.dropbutton-wrapper,
+.dropbutton-widget {
+  max-width: 100%;
+}
+.dropbutton-wrapper {
+  min-height: 1em;
+  position: relative;
+}
+.dropbutton-widget {
+  display: block;
+}
+/* UL styles are over-scoped in core, so this selector needs weight parity. */
+.dropbutton-widget .dropbutton-content {
+  list-style-image: none;
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+.dropbutton-content li,
+.dropbutton-content a {
+  display: block;
+}
+
+/**
+ * The dropbutton styling.
+ *
+ * A dropbutton is a widget that displays a list of action links as a button
+ * with a primary action. Secondary actions are hidden behind a click on a
+ * twisty arrow.
+ *
+ * The arrow is created using border on a zero-width, zero-height span.
+ * The arrow inherits the link color, but can be overridden with border colors.
+ */
+.dropbutton-multiple .dropbutton-widget {
+  padding-right: 2em; /* LTR */
+}
+.dropbutton-widget {
+  display: block;
+  position: absolute;
+  right: 0; /* LTR */
+}
+.dropbutton-multiple.open,
+.dropbutton-multiple.open .dropbutton-widget {
+  max-width: none;
+}
+.dropbutton-multiple.open {
+  z-index: 100;
+}
+.dropbutton-multiple .dropbutton-content .secondary-actions {
+  display: none;
+}
+.dropbutton-multiple.open .dropbutton-content .secondary-actions {
+  display: block;
+}
+.dropbutton-link {
+  bottom: 0;
+  display: block;
+  overflow: hidden;
+  position: absolute;
+  right: 0; /* LTR */
+  text-indent: 110%;
+  top: 0;
+  white-space: nowrap;
+  width: 2em;
+}
+.dropbutton-arrow {
+  border-bottom-color: transparent;
+  border-left-color: transparent;
+  border-right-color: transparent;
+  border-style: solid;
+  border-width: 0.3333em 0.3333em 0;
+  display: block;
+  height: 0;
+  line-height: 0;
+  position: absolute;
+  right: 0.6667em; /* LTR */
+  top: 0.767em;
+  width: 0;
+}
+.dropbutton-multiple.open .dropbutton-arrow {
+  border-bottom: 0.3333em solid;
+  border-top-color: transparent;
+  top: 0.333em;
+}
diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js
new file mode 100644
index 0000000..6d75fae
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.js
@@ -0,0 +1,152 @@
+(function ($, Drupal) {
+
+"use strict";
+
+/**
+ * Process elements with the .dropbutton class on page load.
+ */
+Drupal.behaviors.dropButton = {
+  attach: function (context, settings) {
+    var $dropbuttons = $(context).find('.dropbutton-wrapper').once('dropbutton');
+    if ($dropbuttons.length) {
+      // Adds the delegated handler that will toggle dropdowns on click.
+      var $body = $('body').once('dropbutton-click');
+      if ($body.length) {
+        $body.on('click', '.dropbutton-link', dropbuttonClickHandler);
+      }
+      // Initialize all buttons.
+      for (var i = 0, il = $dropbuttons.length; i < il; i++) {
+        DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings.dropbutton));
+      }
+    }
+  }
+};
+
+/**
+ * Delegated callback for for opening and closing dropbutton secondary actions.
+ */
+function dropbuttonClickHandler (e) {
+  e.preventDefault();
+  $(e.target).closest('.dropbutton-wrapper').toggleClass('open');
+}
+
+/**
+ * A DropButton presents an HTML list as a button with a primary action.
+ *
+ * All secondary actions beyond the first in the list are presented in a
+ * dropdown list accessible through a toggle arrow associated with the button.
+ *
+ * @param {jQuery} $dropbutton
+ *   A jQuery element.
+ *
+ * @param {Object} settings
+ *   A list of options including:
+ *    - {String} title: The text inside the toggle link element. This text is
+ *      hidden from visual UAs.
+ */
+function DropButton (dropbutton, settings) {
+  // Merge defaults with settings.
+  var options = $.extend({'title': Drupal.t('More')}, settings);
+  var $dropbutton = $(dropbutton);
+  this.$dropbutton = $dropbutton;
+  this.$list = $dropbutton.find('.dropbutton');
+  this.$actions = this.$list.find('li');
+
+  // Move the classes from .dropbutton up to .dropbutton-wrapper
+  this.$dropbutton.addClass(this.$list[0].className);
+  this.$dropbutton.attr('id', this.$list[0].id);
+  this.$list.attr({id: '', 'class': 'dropbutton-content'});
+
+  // Add the special dropdown only if there are hidden actions.
+  if (this.$actions.length > 1) {
+    // Remove the first element of the collection and create a new jQuery
+    // collection for the secondary actions.
+    $(this.$actions.splice(1)).addClass('secondary-actions');
+    // Add toggle link.
+    this.$list.before(Drupal.theme('dropbuttonToggle', options));
+    // Bind mouse events.
+    this.$dropbutton.addClass('dropbutton-multiple')
+      .on({
+        /**
+         * Adds a timeout to close the dropdown on mouseleave.
+         */
+        'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
+        /**
+         * Clears timeout when mouseout of the dropdown.
+         */
+        'mouseenter.dropbutton': $.proxy(this.hoverIn, this)
+      });
+  }
+}
+
+/**
+ * Extend the DropButton constructor.
+ */
+$.extend(DropButton, {
+  /**
+   * Store all processed DropButtons.
+   *
+   * @type {Array}
+   */
+  dropbuttons: []
+});
+
+/**
+ * Extend the DropButton prototype.
+ */
+$.extend(DropButton.prototype, {
+  /**
+   * Toggle the dropbutton open and closed.
+   *
+   * @param {Boolean} show
+   *   (optional) Force the dropbutton to open by passing true or to close by
+   *   passing false.
+   */
+  toggle: function (show) {
+    var isBool = typeof show === 'boolean';
+    show = isBool ? show : !this.$dropbutton.hasClass('open');
+    this.$dropbutton.toggleClass('open', show);
+  },
+
+  hoverIn: function () {
+    // Clear any previous timer we were using.
+    if (this.timerID) {
+      window.clearTimeout(this.timerID);
+    }
+  },
+
+  hoverOut: function () {
+    // Wait half a second before closing.
+    this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
+  },
+
+  open: function () {
+    this.toggle(true);
+  },
+
+  close: function () {
+    this.toggle(false);
+  }
+});
+
+
+$.extend(Drupal.theme, {
+  /**
+   * A toggle is an interactive element often bound to a click handler.
+   *
+   * @param {Object} options
+   *   - {String} title: (optional) The HTML anchor title attribute and text for the
+   *     inner span element.
+   *
+   * @return {String}
+   *   A string representing a DOM fragment.
+   */
+  dropbuttonToggle: function (options) {
+    return '<a href="#" class="dropbutton-link" title="' + options.title + '"><span class="dropbutton-arrow"><span class="element-invisible">' + options.title + '</span></span></a>';
+  }
+});
+
+// Expose constructor in the public space.
+Drupal.DropButton = DropButton;
+
+})(jQuery, Drupal);
diff --git a/core/misc/dropbutton/dropbutton.theme-rtl.css b/core/misc/dropbutton/dropbutton.theme-rtl.css
new file mode 100644
index 0000000..9d6456c
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.theme-rtl.css
@@ -0,0 +1,14 @@
+
+/**
+ * @file
+ * General RTL styles for dropbuttons.
+ */
+
+.dropbutton-multiple .dropbutton-content {
+  border-left: 1px solid #e8e8e8;
+  border-right: 0 none;
+}
+.dropbutton-multiple .dropbutton-content li > * {
+  margin-left: 0.25em;
+  margin-right: 0;
+}
diff --git a/core/misc/dropbutton/dropbutton.theme.css b/core/misc/dropbutton/dropbutton.theme.css
new file mode 100644
index 0000000..9c54b73
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.theme.css
@@ -0,0 +1,31 @@
+
+/**
+ * @file
+ * General styles for dropbuttons.
+ */
+
+.dropbutton-wrapper {
+  cursor: pointer;
+  min-height: 2em;
+}
+.dropbutton-widget {
+  background-color: white;
+  border: 1px solid #cccccc;
+}
+.dropbutton-widget:hover {
+  border-color: #b8b8b8;
+}
+.dropbutton-content li > * {
+  overflow: hidden;
+  padding: 0.2em 0.5em;
+  white-space: nowrap;
+}
+.dropbutton-content li + li {
+  border-top: 1px solid #e8e8e8;
+}
+.dropbutton-multiple .dropbutton-content {
+  border-right: 1px solid #e8e8e8; /* LTR */
+}
+.dropbutton-multiple .dropbutton-content li > * {
+  margin-right: 0.25em; /* LTR */
+}
diff --git a/core/modules/system/system.base.css b/core/modules/system/system.base.css
index 610d94d..c50b085 100644
--- a/core/modules/system/system.base.css
+++ b/core/modules/system/system.base.css
@@ -1,4 +1,3 @@
-
 /**
  * @file
  * Generic theme-independent base styles.
@@ -144,6 +143,7 @@ div.tree-child-horizontal {
 table.sticky-header {
   background-color: #fff;
   margin-top: 0;
+  z-index: 500;
 }
 
 /**
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index b41bf08..f972f02 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1380,6 +1380,26 @@ function system_library_info() {
     ),
   );
 
+  // Dropbutton.
+  $libraries['drupal.dropbutton'] = array(
+    'title' => 'Dropbutton',
+    'website' => 'http://drupal.org/node/1608878',
+    'version' => '1.0',
+    'js' => array(
+      'core/misc/dropbutton/dropbutton.js' => array(),
+    ),
+    'css' => array(
+      'core/misc/dropbutton/dropbutton.base.css' => array(),
+      'core/misc/dropbutton/dropbutton.theme.css' => array(),
+    ),
+    'dependencies' => array(
+      array('system', 'jquery'),
+      array('system', 'drupal'),
+      array('system', 'drupalSettings'),
+      array('system', 'jquery.once'),
+    ),
+  );
+
   // Vertical Tabs.
   $libraries['drupal.vertical-tabs'] = array(
     'title' => 'Vertical Tabs',
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index 6187361..91a22c1 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -58,6 +58,19 @@ function theme_test_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
+
+  $items['theme-test'] = array(
+    'title' => 'Theme test',
+    'page callback' => 'system_admin_menu_block_page',
+    'access callback' => TRUE,
+    'file path' => drupal_get_path('module', 'system'),
+    'file' => 'system.admin.inc',
+  );
+  $items['theme-test/list/operations'] = array(
+    'title' => 'Operations',
+    'page callback' => '_theme_test_list_operations',
+    'access callback' => TRUE,
+  );
   return $items;
 }
 
@@ -146,3 +159,78 @@ function theme_test_preprocess_html(&$variables) {
 function theme_theme_test_foo($variables) {
   return $variables['foo'];
 }
+
+/**
+ * Page callback for manual testing of operation links.
+ */
+function _theme_test_list_operations() {
+  $build = array(
+    '#theme' => 'table',
+    '#header' => array('Label', 'Created', 'Operations'),
+    '#rows' => array(),
+  );
+  // Add an item with a very long label, using common operations.
+  $build['#rows']['long']['label'] = l('An item with a very insanely long label, which offers quite a couple of common operations', 'item/long');
+  $build['#rows']['long']['created'] = format_interval(3200);
+  $build['#rows']['long']['operations'] = array(
+    'data' => array(
+      '#theme' => 'dropbutton__node_operations',
+      '#links' => array(
+        'edit' => array(
+          'title' => 'edit',
+          'href' => 'item/long/edit',
+        ),
+        'disable' => array(
+          'title' => 'disable',
+          'href' => 'item/long/disable',
+        ),
+        'clone' => array(
+          'title' => 'clone',
+          'href' => 'item/long/clone',
+        ),
+        'delete' => array(
+          'title' => 'delete',
+          'href' => 'item/long/delete',
+        ),
+      ),
+    ),
+  );
+
+  // Add another item, using common operations.
+  $build['#rows']['another']['label'] = l('Another item, using common operations', 'item/another');
+  $build['#rows']['another']['created'] = format_interval(8600);
+  $build['#rows']['another']['operations'] = $build['#rows']['long']['operations'];
+
+  // Add an item with only one operation.
+  $build['#rows']['one']['label'] = l('An item with only one operation', 'item/one');
+  $build['#rows']['one']['created'] = format_interval(12400);
+  $build['#rows']['one']['operations'] = array(
+    'data' => array(
+      '#theme' => 'dropbutton__node_operations',
+      '#links' => array(
+        'edit' => array(
+          'title' => 'edit',
+          'href' => 'item/long/edit',
+        ),
+      ),
+    ),
+  );
+
+  // Add an item that can only be viewed.
+  $build['#rows']['view']['label'] = l('An item that can only be viewed', 'item/view');
+  $build['#rows']['view']['created'] = format_interval(12400);
+  $build['#rows']['view']['operations'] = array(
+    'data' => array(
+      '#theme' => 'dropbutton__node_operations',
+      '#links' => array(),
+    ),
+  );
+
+  // Add an item for which the default operation is denied.
+  $build['#rows']['denied']['label'] = l('An item for which the default operation is denied', 'item/denied');
+  $build['#rows']['denied']['created'] = format_interval(18600);
+  $build['#rows']['denied']['operations'] = $build['#rows']['long']['operations'];
+  unset($build['#rows']['denied']['operations']['data']['#links']['edit']);
+
+  return $build;
+}
diff --git a/core/themes/bartik/css/style.css b/core/themes/bartik/css/style.css
index 9446e25..aa448e7 100644
--- a/core/themes/bartik/css/style.css
+++ b/core/themes/bartik/css/style.css
@@ -1608,6 +1608,19 @@ div.admin-panel .description {
   margin: 0;
 }
 
+/* ---------- Dropbutton ----------- */
+.dropbutton-widget {
+  background-color: white;
+  border-radius: 5px;
+}
+.dropbutton-widget:hover {
+  background-color: #f8f8f8;
+  border-color: #b8b8b8;
+}
+.dropbutton-multiple.open .dropbutton-widget:hover {
+  background-color: white;
+}
+
 /* ----------- media queries ------------------------------- */
 
 @media all and (min-width: 461px) and (max-width: 900px) {
diff --git a/core/themes/seven/style.css b/core/themes/seven/style.css
index 24b0035..2a896b3 100644
--- a/core/themes/seven/style.css
+++ b/core/themes/seven/style.css
@@ -992,3 +992,26 @@ div.add-or-remove-shortcuts {
   color: #fff;
   border-radius: 8px;
 }
+
+/* Dropbutton */
+.dropbutton-widget {
+  background-color: #fff;
+  background-image: -moz-linear-gradient(-90deg, rgba(255, 255, 255, 0), #e7e7e7);
+  background-image: -o-linear-gradient(-90deg, rgba(255, 255, 255, 0), #e7e7e7);
+  background-image: -webkit-linear-gradient(-90deg, rgba(255, 255, 255, 0), #e7e7e7);
+  background-image: linear-gradient(-90deg, rgba(255, 255, 255, 0), #e7e7e7);
+  border-radius: 5px;
+}
+.dropbutton-widget:hover {
+  background-color: #f0f0f0;
+  border-color: #b8b8b8;
+}
+.dropbutton-multiple.open .dropbutton-widget:hover {
+  background-color: #fff;
+}
+.dropbutton-content li:first-child > * {
+  text-overflow: ellipsis;
+}
+.dropbutton-multiple.open .dropbutton-content li:first-child > * {
+  text-overflow: clip;
+}
