diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 7766952..1caebfa 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1691,6 +1691,46 @@ function theme_links($variables) {
 }
 
 /**
+ * Builds a render array for theme_dropbutton().
+ */
+function template_preprocess_dropbutton(&$variables) {
+  $variables['attributes']['class'][] = 'dropbutton';
+  $variables['attributes']['id'] = drupal_html_id('dropbutton');
+  $variables['element'] = array(
+    '#theme' => 'links',
+    '#links' => $variables['links'],
+    '#attributes' => $variables['attributes'],
+    '#attached' => array(
+      'library' => array(
+        array('system', 'drupal.dropbutton'),
+      ),
+    ),
+  );
+  // 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
@@ -2843,6 +2883,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..8eca580
--- /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 * {
+  -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;
+}
+.dropbutton-widget {
+  display: inline-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 {
+  position: relative;
+}
+.dropbutton-multiple .dropbutton-widget {
+  display: block;
+  padding-right: 2em; /* LTR */
+  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.667em;
+  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..ec62757
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.js
@@ -0,0 +1,189 @@
+(function ($, Drupal, window) {
+
+"use strict";
+
+/**
+ * Process elements with the .dropbutton class on page load.
+ */
+Drupal.behaviors.dropButton = {
+  attach: function (context, settings) {
+    settings = ('dropbutton' in settings) ? settings.dropbutton : {};
+    var $dropbuttons = $(context).find('.dropbutton').once('dropbutton');
+    for (var i = 0, il = $dropbuttons.length; i < il; i++) {
+      DropButton.dropbuttons.push(new DropButton($dropbuttons[i], settings));
+    }
+  }
+};
+
+/**
+ * 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 {DOMElement} dropbutton
+ *   An HTMLListElement.
+ * @param {Object} options
+ *   A list of options including:
+ *    - title: The text inside the toggle link element. This text is hidden from
+ *      visual UAs.
+ */
+function DropButton (dropbutton, settings) {
+  this.dropbutton = dropbutton;
+  this.$list = $(dropbutton);
+  // State properties.
+  this.isOpen = false;
+  this.isHovered = false;
+  this.timerID = 0;
+  // Merge defaults with settings.
+  this.defaults = {
+    'title': Drupal.t('More')
+  };
+  var options = $.extend(this.defaults, settings);
+  // Build the view.
+  this.build(options);
+}
+
+/**
+ * Extend the DropButton constructor.
+ */
+$.extend(DropButton, {
+  /**
+   * Store all processed DropButtons.
+   *
+   * @type {Array}
+   */
+  dropbuttons: []
+});
+
+/**
+ * Extend the DropButton prototype.
+ */
+$.extend(DropButton.prototype, {
+  /**
+   * Render the dropbutton view.
+   */
+  build: function (options) {
+    // Save the ID and class attributes so that they can be applied to the
+    // widget wrapper below.
+    options.id = this.$list.attr('id') || '';
+    options['class'] = this.$list.attr('class').split(' ') || [];
+    options['class'].push('dropbutton-wrapper');
+    // Remove the class and ID attributes. The values of these attributes
+    // will be applied to the dropbutton wrapper.
+    this.$list.removeAttr('class id');
+    // Mark-up the list with dropbutton structure.
+    this.$list.addClass('dropbutton-content');
+    // Mark the secondary actions.
+    this.$secondaryActions = this.$list
+      .find('li')
+      .not(':first')
+      .addClass('secondary-actions');
+    // Add a class to indicate the dropbutton has more than one action.
+    if (this.$secondaryActions.length) {
+      options['class'].push('dropbutton-multiple');
+    }
+    // Theme the output.
+    this.$dropbutton = this.$list
+      .wrap($(Drupal.theme.dropbutton(options)))
+      .closest('.dropbutton-wrapper')
+      // Add a toggle if this dropbutton has multiple actions.
+      .filter('.dropbutton-multiple')
+      .children('.dropbutton-widget')
+      // Build and insert the dropbutton toggle.
+      .prepend(Drupal.theme.toggle(options))
+      // Stop the children traversal and return to $dropbutton.
+      .end()
+      // Bind events.
+      .on({
+        'mouseenter.dropbutton': $.proxy(this, 'hoverIn'),
+        'mouseleave.dropbutton': $.proxy(this, 'hoverOut')
+      })
+      .on({
+        'click.dropbutton': $.proxy(this, 'toggleClickHandler')
+      }, '.dropbutton-link');
+  },
+
+  hoverIn: function () {
+    // Clear any previous timer we were using.
+    if (this.timerID) {
+      window.clearTimeout(this.timerID);
+    }
+    this.isHovered = true;
+  },
+
+  hoverOut: function () {
+    this.isHovered = false;
+    this.toggle();
+  },
+
+  toggleClickHandler: function (event) {
+    event.preventDefault();
+    var closeIt = (this.isOpen) ? true : false;
+    this.toggle(closeIt);
+  },
+
+  /**
+   * Toggle the dropbutton open and closed.
+   *
+   * @param {Boolean} closeIt
+   *   (optional) Force the dropbutton to close by passing true or to close by
+   *   passing false.
+   */
+  toggle: function (closeIt) {
+    // Open or close the dropbutton immediately if closeIt is defined.
+    if (closeIt !== undefined) {
+      this[(closeIt) ? 'close' : 'open']();
+      return;
+    }
+    // If the dropbutton is open and the dropbutton is not hovered,
+    // then prepare to close it.
+    if (this.isOpen && !this.isHovered) {
+      // Wait half a second before closing.
+      this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
+    }
+  },
+
+  close: function () {
+    this.isOpen = false;
+    this.$dropbutton.removeClass('open');
+  },
+
+  open: function () {
+    this.isOpen = true;
+    this.$dropbutton.addClass('open');
+  }
+});
+
+/**
+ * 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.
+ */
+Drupal.theme.toggle = function (options) {
+  return '<a href="#" class="dropbutton-link" title="' + options.title + '"><span class="dropbutton-arrow"><span class="element-invisible">' + options.title + '</span></span></a>';
+};
+
+/**
+ * A wrapping DOM fragment representing a dropbutton widget.
+ *
+ * @param Object options
+ *   - String id: (optional) An ID to apply to the outer wrapping div.
+ *   - Array class: (optional) Classes to apply to the outer wrapping div.
+ *
+ * @return String
+ *   A string representing a DOM fragment.
+ */
+Drupal.theme.dropbutton = function (options) {
+  return '<div id="' + options.id + '" class="' + options['class'].join(' ') + '"><div class="dropbutton-widget"></div></div>';
+};
+
+// Expose constructor in the public space.
+Drupal.DropButton = DropButton;
+
+})(jQuery, Drupal, window);
diff --git a/core/misc/dropbutton/dropbutton.theme-rtl.css b/core/misc/dropbutton/dropbutton.theme-rtl.css
new file mode 100644
index 0000000..a5c6c4e
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.theme-rtl.css
@@ -0,0 +1,10 @@
+
+/**
+ * @file
+ * General RTL styles for dropbuttons.
+ */
+
+.dropbutton-multiple .dropbutton-content {
+  border-left: 1px solid #e8e8e8;
+  border-right: 0 none;
+}
diff --git a/core/misc/dropbutton/dropbutton.theme.css b/core/misc/dropbutton/dropbutton.theme.css
new file mode 100644
index 0000000..2e52c1c
--- /dev/null
+++ b/core/misc/dropbutton/dropbutton.theme.css
@@ -0,0 +1,32 @@
+
+/**
+ * @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 {
+  line-height: 1.333;
+}
+.dropbutton-content li > * {
+  margin-right: 0.3333em;
+  overflow: hidden;
+  padding: 0.25em 0.75em;
+  white-space: nowrap;
+}
+.dropbutton-content li + li {
+  border-top: 1px solid #e8e8e8;
+}
+.dropbutton-multiple .dropbutton-content {
+  border-right: 1px solid #e8e8e8; /* LTR */
+}
diff --git a/core/modules/system/system.base.css b/core/modules/system/system.base.css
index 610d94d..f6bf7f9 100644
--- a/core/modules/system/system.base.css
+++ b/core/modules/system/system.base.css
@@ -144,6 +144,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 e5dc768..b03f647 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1392,6 +1392,25 @@ 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', 'jquery.once'),
+      array('system', 'drupal'),
+    ),
+  );
+
   // 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 7532a4a..8dfba0b 100644
--- a/core/themes/bartik/css/style.css
+++ b/core/themes/bartik/css/style.css
@@ -1609,6 +1609,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 ebaa86b..ad66c73 100644
--- a/core/themes/seven/style.css
+++ b/core/themes/seven/style.css
@@ -964,3 +964,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;
+}
