diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 0ff5fb09ec..6226cc46dd 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -214,6 +214,20 @@ drupal.dropbutton:
     - core/drupalSettings
     - core/jquery.once
 
+drupal.splitbutton:
+  version: VERSION
+  js:
+    misc/splitbutton/splitbutton.js: {}
+  css:
+    component:
+      misc/splitbutton/splitbutton.css: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
+    - core/drupalSettings
+    - core/jquery.once
+    - core/popperjs
+
 drupal.entity-form:
   version: VERSION
   js:
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index d2d54979b7..53c256da13 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1178,6 +1178,141 @@ function template_preprocess_container(&$variables) {
   $variables['attributes'] = $element['#attributes'];
 }
 
+/**
+ * Prepares variables for splitbutton templates.
+ *
+ * Default template: splitbutton.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties of the element.
+ *     Properties used: #id, #attributes.
+ */
+function template_preprocess_splitbutton(array &$variables) {
+  $element = $variables['element'];
+  $element += [
+    '#attributes' => [],
+    '#content_attributes' => [],
+    '#splitbutton_type' => [],
+  ];
+
+  // Attach the library and the required CSS classes.
+  $variables['#attached']['library'][] = 'core/drupal.splitbutton';
+  if (!isset($variables['#attached']['drupalSettings']['splitbutton'])) {
+    $variables['#attached']['drupalSettings']['splitbutton'] = [];
+  }
+  $variables['#attached']['drupalSettings']['splitbutton'] +=[
+    'triggerLabelDefault' => t('List additional actions'),
+  ];
+
+  $element['#attributes']['class'][] = 'js-splitbutton';
+  $element['#content_attributes']['class'][] = 'js-splitbutton-list';
+
+  if (empty($element['#content_attributes']['id'])) {
+    $base = isset($variables['element']['#id']) ? $variables['element']['#id'] . '-' : '';
+    $element['#content_attributes']['id'] = Html::getUniqueId($base . 'splitbutton-list');
+  }
+
+  if (empty($element['#attributes']['id'])) {
+    $base = isset($variables['element']['#id']) ? $variables['element']['#id'] . '-' : '';
+    $element['#attributes']['id'] = Html::getUniqueId($base . 'splitbutton');
+  }
+
+  if (!is_array($element['#splitbutton_type'])) {
+    $element['#splitbutton_type'] = [$element['#splitbutton_type']];
+  }
+  foreach ($element['#splitbutton_type'] as $type) {
+    $element['#attributes']['class'][] = Html::getClass('splitbutton--' . $type);
+  }
+
+  $variables += [
+    'main_items' => [],
+    'items' => [],
+  ];
+
+  foreach (Element::children($element) as $key) {
+    $group = !isset($variables['main_items']) || empty($variables['main_items']) ? 'main_items' : 'items';
+    if (isset($variables['element'][$key]['#splitbutton_main_item'])) {
+      $group = 'main_items';
+    }
+    if (isset($element['#main_items']) && empty($element['#main_items'])) {
+      $group = 'items';
+    }
+    $variables[$group][$key]['value'] = $element[$key];
+    $variables[$group][$key]['attributes'] = new Attribute([
+      'role' => $element['#use_aria_menu_role'] ? 'none' : NULL,
+    ]);
+
+    // If the current element is a link, we have to add the required attributes
+    // to  $link['#options']['attributes'].
+    // @see \Drupal\Core\Render\Element\Link::preRenderLink
+    if ($variables[$group][$key]['value']['#type'] === 'link' && isset($variables[$group][$key]['value']['#options']['attributes']) && !empty($variables[$group][$key]['value']['#options']['attributes'])) {
+      $variables[$group][$key]['value']['#options']['attributes']['class'][] = 'splitbutton__action';
+    }
+    else {
+      $variables[$group][$key]['value']['#attributes']['class'][] = 'splitbutton__action';
+    }
+
+    unset($variables[$group][$key]['value']['#markup']);
+    unset($variables[$group][$key]['value']['#children']);
+    unset($variables[$group][$key]['value']['#printed']);
+  }
+
+  foreach ($variables['main_items'] as &$main_item) {
+    if ($main_item['value']['#type'] === 'link' && isset($main_item['value']['#options']['attributes'])) {
+      $main_item['value']['#options']['attributes']['class'][] = 'splitbutton__action--main';
+    }
+    else {
+      $main_item['value']['#attributes']['class'][] = 'splitbutton__action--main';
+    }
+  }
+
+  foreach ($variables['items'] as &$item) {
+    if ($item['value']['#type'] === 'link' && isset($item['value']['#options']['attributes'])) {
+      $item['value']['#options']['attributes']['role'] = $element['#use_aria_menu_role'] ? 'menuitem' : NULL;
+      $item['value']['#options']['attributes']['class'][] = 'splitbutton__action--secondary';
+      $item['value']['#options']['attributes']['class'][] = 'js-splitbutton-action-secondary';
+    }
+    else {
+      $item['value']['#attributes']['role'] = $element['#use_aria_menu_role'] ? 'menuitem' : NULL;
+      $item['value']['#attributes']['class'][] = 'splitbutton__action--secondary';
+      $item['value']['#attributes']['class'][] = 'js-splitbutton-action-secondary';
+    }
+    $item['attributes']->setAttribute('role', $element['#use_aria_menu_role'] ? 'none' : NULL);
+  }
+
+  $variables['multiple'] = count($variables['items']) > 0;
+
+  // Special handling for form elements.
+  if (isset($element['#array_parents'])) {
+    // Assign an html ID.
+    if (!isset($element['#attributes']['id'])) {
+      $element['#attributes']['id'] = $element['#id'];
+    }
+  }
+
+  $splitbutton_id = $element['#attributes']['id'];
+  $list_id = $element['#content_attributes']['id'];
+  $button_id = Html::getUniqueId($list_id . '-toggle');
+  $instance_settings = [
+    'listId' => $list_id,
+    'buttonId' => $button_id,
+    'noMainItems' => empty($element['#main_items']) && empty($variables['main_items']),
+    'triggerLabel' => !empty($element['#trigger_label']) ? (string) $element['#trigger_label'] : NULL,
+    'triggerLabelVisible' => !empty($element['#trigger_label_visible']),
+  ];
+  $variables['#attached']['drupalSettings']['splitbutton']['instances'][$splitbutton_id] = array_filter($instance_settings);
+
+  $variables['trigger_label'] = !empty($element['#trigger_label']) ? $element['#trigger_label'] : $variables['#attached']['drupalSettings']['splitbutton']['triggerLabelDefault'];
+  $variables['trigger_label_visible'] = !empty($element['#trigger_label_visible']);
+
+  $variables['attributes'] = $element['#attributes'];
+  $variables['content_attributes'] = [
+    'role' => $element['#use_aria_menu_role'] ? 'menu' : NULL,
+    'aria-labelledby' => $button_id,
+  ] + $element['#content_attributes'];
+}
+
 /**
  * Prepares variables for maintenance task list templates.
  *
@@ -1882,6 +2017,9 @@ function drupal_common_theme() {
     'container' => [
       'render element' => 'element',
     ],
+    'splitbutton' => [
+      'render element' => 'element',
+    ],
     // From field system.
     'field' => [
       'render element' => 'element',
diff --git a/core/lib/Drupal/Core/Entity/EntityListBuilder.php b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
index d07e82c3a8..65f57e4de4 100644
--- a/core/lib/Drupal/Core/Entity/EntityListBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
@@ -205,8 +205,8 @@ public function buildRow(EntityInterface $entity) {
    */
   public function buildOperations(EntityInterface $entity) {
     $build = [
-      '#type' => 'operations',
-      '#links' => $this->getOperations($entity),
+      '#type' => 'splitbutton_operations',
+      '#items' => $this->getOperations($entity),
     ];
 
     return $build;
diff --git a/core/lib/Drupal/Core/Render/Element/OperationsSplitbutton.php b/core/lib/Drupal/Core/Render/Element/OperationsSplitbutton.php
new file mode 100644
index 0000000000..f9221d18c7
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/OperationsSplitbutton.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\Core\Render\Element;
+
+/**
+ * Provides am alternative element for entity operations.
+ *
+ * @todo Class comment.
+ *
+ * @see \Drupal\Core\Render\Element\Splitbutton.
+ *
+ * @RenderElement("splitbutton_operations")
+ */
+class OperationsSplitbutton extends Splitbutton {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preRenderSplitbutton($element) {
+    $element = parent::preRenderSplitbutton($element);
+
+    if (($splitbutton_theme_wrapper_key = array_search('splitbutton', $element['#theme_wrappers'])) !== FALSE) {
+      unset($element['#theme_wrappers'][$splitbutton_theme_wrapper_key]);
+    }
+    array_unshift($element['#theme_wrappers'], 'splitbutton__operations');
+
+    return $element;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Render/Element/Splitbutton.php b/core/lib/Drupal/Core/Render/Element/Splitbutton.php
new file mode 100644
index 0000000000..9a6f9c9360
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/Splitbutton.php
@@ -0,0 +1,171 @@
+<?php
+
+namespace Drupal\Core\Render\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+
+/**
+ * Provides a render element for links and buttons rendered as a dropdown.
+ *
+ * @todo
+ *
+ * Properties:
+ * - #items: list of the renderable splitbutton items (supported: types are
+ *   'submit', 'button' and 'link'), or links actions in the form what the
+ *   'links' theme function accepts. See template_preprocess_links() for the
+ *   documentation the properties of links in this array.
+ * - #use_aria_menu_role: TRUE (if no buttons).
+ * - #splitbutton_type: A string ot an array of strings defining types of
+ *   splitbutton variant for styling proposes. Renders as class
+ *  `splitbutton--#splitbutton_type`.
+ * - #trigger_label: The label for the trigger button. Defaults to
+ *   'List additional actions'. This label is visible if #main_items is set to
+ *   FALSE.
+ * - #trigger_label_visible: FALSE.
+ * - #main_items: TRUE
+ *
+ * @see \Drupal\Core\Render\Element\SplitbuttonOperations
+ *
+ * @RenderElement("splitbutton")
+ */
+class Splitbutton extends RenderElement {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    $class = get_class($this);
+    return [
+      '#process' => [
+        [$class, 'processButtons'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderSplitbutton'],
+      ],
+      '#theme_wrappers' => [],
+      '#main_items' => TRUE,
+      '#use_aria_menu_role' => TRUE,
+      '#trigger_label_visible' => FALSE,
+      '#items' => [],
+    ];
+  }
+
+  /**
+   * Processes items of the splitbutton.
+   *
+   * Move every splitbutton items from '#items' key to the array root for
+   * FormBuilder.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   splitbutton.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   *
+   * @return array
+   *   The processed splitbutton element.
+   */
+  public static function processButtons(&$element, FormStateInterface $form_state, &$complete_form) {
+    self::prepareSplitbuttonItems($element);
+    return $element;
+  }
+
+  /**
+   * Pre-renders Splitbutton.
+   *
+   * @param array $element
+   *   An associative array containing the properties of the splitbutton
+   *   element.
+   *
+   * @return array
+   *   The $element with the prepared variables.
+   */
+  public static function preRenderSplitbutton(array $element) {
+    self::prepareSplitbuttonItems($element);
+    $child_keys = Element::children($element);
+
+    foreach ($child_keys as $child_key) {
+      $button_types = ['submit', 'button'];
+      $child_is_legacy_link = !empty($element[$child_key]['#legacy_link']);
+      $child_is_button = isset($element[$child_key]['#type']) && in_array($element[$child_key]['#type'], $button_types);
+
+      if ($child_is_legacy_link) {
+        $element[$child_key] = self::convertLegacyLinkElement($element[$child_key]['#legacy_link']);
+      }
+
+      if ($child_is_button) {
+        $element['#use_aria_menu_role'] = FALSE;
+      }
+    }
+
+    array_unshift($element['#theme_wrappers'], 'splitbutton');
+
+    return $element;
+  }
+
+  /**
+   * Converts a legacy link item to a link renderable.
+   *
+   * @param array $link_data
+   *   A 'links' item.
+   *   @see template_preprocess_links().
+   *
+   * @return array
+   *   The renderable link element array.
+   */
+  private static function convertLegacyLinkElement(array $link_data) {
+    if (empty($link_data['url'])) {
+      return ['#markup' => $link_data['title']];
+    }
+
+    $link_data += ['ajax' => NULL];
+    $keys = ['title', 'url'];
+
+    return [
+      '#type' => 'link',
+      '#title' => $link_data['title'],
+      '#options' => array_diff_key($link_data, array_combine($keys, $keys)),
+      '#url' => $link_data['url'],
+      '#ajax' => $link_data['ajax'],
+    ];
+  }
+
+  /**
+   * Prepares Splitbutton items.
+   *
+   * Changes the element structure by moving the supported items to array root
+   * and removes the unsupported items.
+   *
+   * @param array $element
+   *   The Splitbutton renderable array.
+   *
+   * @param array
+   *   The prepared Splitbutton renderable array.
+   */
+  private static function prepareSplitbuttonItems(array &$element) {
+    if (empty($element['#splitbutton_items_prepared'])) {
+      $supported_types = ['submit', 'button', 'link'];
+      $child_keys = Element::children($element['#items']);
+
+      foreach ($child_keys as $child_key) {
+        if (isset($element['#items'][$child_key]['#type']) && in_array($element['#items'][$child_key]['#type'], $supported_types)) {
+          $element[$child_key] = $element['#items'][$child_key];
+        }
+        elseif (isset($element['#items'][$child_key]['title'])) {
+          // This is a legacy link.
+          $element[$child_key]['#legacy_link'] = $element['#items'][$child_key];
+        }
+        else {
+          // Unsupported item type.
+          unset($element['#items'][$child_key]);
+        }
+      }
+
+      $element['#splitbutton_items_prepared'] = TRUE;
+    }
+  }
+
+}
diff --git a/core/misc/splitbutton/splitbutton.css b/core/misc/splitbutton/splitbutton.css
new file mode 100644
index 0000000000..a9fbf609e7
--- /dev/null
+++ b/core/misc/splitbutton/splitbutton.css
@@ -0,0 +1,154 @@
+/**
+ * @file
+ * Base styles for splitbuttons.
+ */
+
+.splitbutton {
+  position: relative;
+  display: inline-block;
+  max-width: 245px;
+}
+
+.splitbutton--small,
+.splitbutton--extrasmall {
+  font-size: 10px;
+  line-height: normal;
+}
+
+.splitbutton__action,
+.splitbutton__toggle {
+  position: relative;
+  display: inline-block;
+  box-sizing: border-box;
+  padding: 0.25em 0.75em;
+  text-align: left; /* LTR */
+  text-decoration: none;
+  color: #000;
+  border: 0;
+  background: #fff;
+  font-size: inherit;
+  line-height: inherit;
+}
+[dir="rtl"] .splitbutton__action,
+[dir="rtl"] .splitbutton__toggle {
+  text-align: right;
+}
+
+.splitbutton__main-items {
+  display: inline-flex;
+}
+
+.splitbutton__action--main,
+.splitbutton__toggle {
+  border: 1px solid #bbb;
+}
+
+.splitbutton__action--main:first-child,
+.splitbutton__toggle:first-child {
+  border-top-left-radius: 2em; /* LTR */
+  border-bottom-left-radius: 2em; /* LTR */
+}
+[dir="rtl"] .splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle:first-child {
+  border-radius: 0 2em 2em 0;
+}
+
+.splitbutton__action--main:first-child + .splitbutton__action--main,
+.splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-left: -1px;
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__action--main,
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-right: -1px;
+  margin-left: 0;
+}
+
+.splitbutton__action--main:last-child,
+.splitbutton__toggle:last-child {
+  margin-right: 0; /* LTR */
+  border-top-right-radius: 2em; /* LTR */
+  border-bottom-right-radius: 2em; /* LTR */
+}
+[dir="rtl"] .splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle:last-child {
+  margin-left: 0;
+  border-radius: 2em 0 0 2em;
+}
+
+/**
+ * Since :first-child:last-child is stronger than :only-child, we don't have to
+ * provide [dir="rtl"] selectors.
+ **/
+.splitbutton__action--main:first-child:last-child,
+.splitbutton__toggle:first-child:last-child {
+  border-radius: 2em;
+}
+
+.splitbutton__toggle {
+  cursor: pointer;
+  white-space: nowrap;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+.splitbutton__toggle--no-label,
+[dir="rtl"] .splitbutton__toggle--no-label {
+  text-align: center;
+}
+
+.splitbutton__toggle-arrow {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  transform: translate(0, -50%);
+  border-width: 0.3333em 0.3333em 0;
+  border-style: solid;
+  border-right-color: transparent;
+  border-left-color: transparent;
+  line-height: 0;
+}
+.splitbutton.open .splitbutton__toggle-arrow {
+  border-top: 0;
+  border-bottom: 0.3333em solid;
+}
+
+.splitbutton__list {
+  z-index: 501;
+  box-sizing: border-box;
+  min-width: 100%;
+  max-width: 245px;
+  margin: 0.25em 0; /* LTR */
+  padding: 0.25em 0;
+  list-style: none;
+  color: #000;
+  border: 1px solid #aaa;
+  border-radius: 0.25em;
+  background: #fff;
+}
+[dir="rtl"] .splitbutton__list {
+  margin: 0.25em 0;
+}
+
+.splitbutton__action--secondary {
+  min-width: 100%;
+  white-space: normal;
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: 0.5em 0.75em;
+}
+
+.js .splitbutton__list:not(.open) {
+  display: none;
+}
+
+.splitbutton__action:focus {
+  z-index: 1;
+}
+
+.splitbutton__action--secondary:hover {
+  color: #000;
+  background: #c7eaff;
+}
diff --git a/core/misc/splitbutton/splitbutton.es6.js b/core/misc/splitbutton/splitbutton.es6.js
new file mode 100644
index 0000000000..5352b1746e
--- /dev/null
+++ b/core/misc/splitbutton/splitbutton.es6.js
@@ -0,0 +1,486 @@
+/**
+ * @file
+ * SplitButton feature.
+ */
+
+(($, Drupal, Popper) => {
+  /**
+   * A SplitButton is an HTML list and at least one item as 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.
+   *
+   * @constructor Drupal.SplitButton
+   *
+   * @param {HTMLElement} splitbutton
+   *   The splitbutton DOM element.
+   * @param {object} options
+   *   A list of options including:
+   * @param {string} options.triggerLabel
+   *   The text inside the toggle link element. This text may be hidden
+   *   from visual UAs.
+   */
+  function SplitButton(splitbutton, options) {
+    // Merge defaults with settings.
+    const _self = this;
+
+    /**
+     * @type {jQuery}
+     */
+    this.$splitbutton = $(splitbutton);
+
+    // Attach ajax progress handler.
+    // This will move the ajax progress indicator added to the splitbutton next
+    // to the splitbutton.
+    $(document).on('ajaxSend.splitbutton', {
+      data: {
+        splitbutton: _self,
+      },
+      handler: _self.moveAjaxProgressIndicator,
+    });
+
+    /**
+     * @type {jQuery}
+     */
+    this.$list = this.$splitbutton.find(`#${options.listId}`);
+
+    if (this.$list.length !== 1) {
+      return;
+    }
+
+    this.expanded = false;
+
+    /**
+     * Secondary actions.
+     *
+     * @type {jQuery}
+     */
+    this.$actions = this.$list.children();
+
+    // Add toggle link.
+    this.$toggle = $(Drupal.theme('splitbuttonToggle', options))
+      .addClass('js-splitbutton-toggle')
+      .attr('aria-haspopup', 'true')
+      .attr('aria-controls', options.listId)
+      .attr('id', options.buttonId)
+      .on({
+        click: {
+          data: _self,
+          handler: _self.toggleClickHandler,
+        },
+        keydown: {
+          data: _self,
+          handler: _self.toggleKeyHandler,
+        },
+      });
+
+    this.$list.on('keydown', this, this.listKeyHandler);
+
+    if (
+      this.$splitbutton.find('.js-splitbutton-toggle-placeholder').length === 1
+    ) {
+      this.$splitbutton
+        .find('.js-splitbutton-toggle-placeholder')
+        .replaceWith(this.$toggle);
+    } else {
+      this.$list.before(this.$toggle);
+    }
+
+    // Bind mouse events.
+    this.$splitbutton.on({
+      /**
+       * Adds a timeout to close the dropdown on mouseleave.
+       *
+       * @ignore
+       */
+      'mouseleave.splitbutton': $.proxy(this.hoverOut, this),
+
+      /**
+       * Clears timeout when mouseout of the dropdown.
+       *
+       * @ignore
+       */
+      'mouseenter.splitbutton': $.proxy(this.hoverIn, this),
+
+      /**
+       * Similar to mouseleave/mouseenter, but for keyboard navigation.
+       *
+       * @ignore
+       */
+      'focusout.splitbutton': $.proxy(this.focusOut, this),
+
+      /**
+       * @ignore
+       */
+      'focusin.splitbutton': $.proxy(this.focusIn, this),
+    });
+
+    this.$list.find('.js-splitbutton-action-secondary').attr('tabindex', -1);
+  }
+
+  /**
+   * Extend the SplitButton constructor.
+   */
+  $.extend(
+    SplitButton,
+    /** @lends Drupal.SplitButton */ {
+      /**
+       * Store all processed SplitButtons.
+       *
+       * @type {Array.<Drupal.SplitButton>}
+       */
+      splitbuttons: [],
+    },
+  );
+
+  /**
+   * Extend the SplitButton prototype.
+   */
+  $.extend(
+    SplitButton.prototype,
+    /** @lends Drupal.SplitButton# */ {
+      /**
+       * Refines ajax progress indicator placement.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       * @param {object} event.data
+       *   Event data object.
+       * @param {Drupal.SplitButton} event.data.splitbutton
+       *   The actual SplitButton instance.
+       */
+      moveAjaxProgressIndicator(event) {
+        const $splitbutton = event.data.splitbutton.$splitbutton;
+        const $throbber = $(Drupal.theme.ajaxProgressThrobber());
+        const $progressBar = Drupal.theme.ajaxProgressBar($('<span></span>'));
+
+        [$throbber[0], $progressBar[0]].forEach(progressNode => {
+          const classSelector = progressNode.className
+            ? `[class="${progressNode.className}"]`
+            : '';
+          const progressSelector = progressNode.tagName + classSelector;
+
+          if (classSelector) {
+            const $progressElementInDocument = $(document).find(
+              progressSelector,
+            );
+            const $progressElementInSplitbutton = $splitbutton.find(
+              progressSelector,
+            );
+
+            if (
+              $progressElementInSplitbutton.length === 1 &&
+              $progressElementInDocument.length === 1
+            ) {
+              $splitbutton.after($progressElementInSplitbutton);
+            }
+          }
+        });
+      },
+
+      /**
+       * Toggle the splitbutton open and closed.
+       *
+       * @param {bool} [show]
+       *   Force the splitbutton to open by passing true or to close by
+       *   passing false.
+       *
+       * @return {Drupal.SplitButton}
+       *   The SplitButton instance.
+       */
+      toggle(show) {
+        const isBool = typeof show === 'boolean';
+        show = isBool ? show : !this.expanded;
+        this.expanded = show;
+        this.$list.toggleClass('open', show);
+        this.$splitbutton.toggleClass('open', show);
+
+        if (show) {
+          this.$toggle.attr('aria-expanded', 'true');
+          this.$list
+            .find('.js-splitbutton-action-secondary')
+            .removeAttr('tabindex');
+
+          if (this.popper) {
+            this.popper.update();
+          } else {
+            const edge =
+              document.documentElement.dir === 'rtl' ? 'start' : 'end';
+            this.popper = new Popper(this.$splitbutton, this.$list, {
+              placement: `bottom-${edge}`,
+              modifiers: {
+                flip: {
+                  enabled: false,
+                },
+                computeStyle: {
+                  gpuAcceleration: false,
+                },
+              },
+            });
+          }
+        } else {
+          this.$toggle.removeAttr('aria-expanded');
+          this.$list
+            .find('.js-splitbutton-action-secondary')
+            .attr('tabindex', -1);
+        }
+
+        return this;
+      },
+
+      /**
+       * Move action focus to the specified direction.
+       *
+       * @param {string} direction
+       *   Can be 'previous', 'next', 'first' or 'last'.
+       */
+      focusAction(direction) {
+        const $listItemFocused = this.$actions.has(':focus');
+        const $listItemFirst = this.$actions.first();
+        const $listItemLast = this.$actions.last();
+        const $nextlistItem = $listItemFocused.next().length
+          ? $listItemFocused.next()
+          : $listItemLast;
+        const $prevlistItem = $listItemFocused.prev().length
+          ? $listItemFocused.prev()
+          : $listItemFirst;
+
+        this.toggle(true);
+
+        /* eslint-disable default-case */
+        switch (direction) {
+          case 'next':
+            $nextlistItem
+              .find(':focusable')
+              .first()
+              .trigger('focus');
+            break;
+
+          case 'previous':
+            $prevlistItem
+              .find(':focusable')
+              .first()
+              .trigger('focus');
+            break;
+
+          case 'first':
+            $listItemFirst
+              .find(':focusable')
+              .first()
+              .trigger('focus');
+            break;
+
+          case 'last':
+            $listItemLast
+              .find(':focusable')
+              .first()
+              .trigger('focus');
+            break;
+        }
+        /* eslint-enable default-case */
+      },
+
+      /**
+       * Delegated callback for toggling secondary splitbutton actions.
+       *
+       * This is an event handler attached to the toggle button.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       * @param {Drupal.SplitButton} event.data
+       *   The actual SplitButton instance.
+       */
+      toggleClickHandler(event) {
+        event.data.toggle();
+        event.preventDefault();
+      },
+
+      /**
+       * Delegated callback for toggling secondary splitbutton actions.
+       *
+       * This is an event handler attached to the toggle button.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       * @param {Drupal.SplitButton} event.data
+       *   The actual SplitButton instance.
+       */
+      toggleKeyHandler(event) {
+        /* eslint-disable default-case */
+        switch (event.key) {
+          case 'ArrowUp':
+            event.data.focusAction('last');
+            event.preventDefault();
+            break;
+
+          case ' ':
+          case 'Enter':
+            event.data.toggle();
+            event.preventDefault();
+            break;
+
+          case 'ArrowDown':
+            event.data.focusAction('first');
+            event.preventDefault();
+            break;
+        }
+        /* eslint-enable default-case */
+      },
+
+      /**
+       * Delegated callback for toggling secondary splitbutton actions.
+       *
+       * This is an event handler attached to the toggle button.
+       *
+       * @param {jQuery.Event} event
+       *   The event triggered.
+       * @param {Drupal.SplitButton} event.data
+       *   The actual SplitButton instance.
+       */
+      listKeyHandler(event) {
+        /* eslint-disable default-case */
+        switch (event.key) {
+          case 'ArrowUp':
+            event.data.focusAction('previous');
+            event.preventDefault();
+            break;
+
+          case 'ArrowDown':
+            event.data.focusAction('next');
+            event.preventDefault();
+            break;
+
+          case 'Home':
+            event.data.focusAction('first');
+            event.preventDefault();
+            break;
+
+          case 'End':
+            event.data.focusAction('last');
+            event.preventDefault();
+            break;
+
+          case 'Escape':
+            event.data.toggle(false).$toggle.trigger('focus');
+            event.preventDefault();
+            break;
+        }
+        /* eslint-enable default-case */
+      },
+
+      /**
+       * @method
+       */
+      hoverIn() {
+        // Clear any previous timer we were using.
+        if (this.timerID) {
+          window.clearTimeout(this.timerID);
+        }
+      },
+
+      /**
+       * @method
+       */
+      hoverOut() {
+        // Wait half a second before closing.
+        this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
+      },
+
+      /**
+       * @method
+       */
+      open() {
+        this.toggle(true);
+      },
+
+      /**
+       * @method
+       */
+      close() {
+        this.toggle(false);
+      },
+
+      /**
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      focusOut(e) {
+        this.hoverOut.call(this, e);
+      },
+
+      /**
+       * @param {jQuery.Event} e
+       *   The event triggered.
+       */
+      focusIn(e) {
+        this.hoverIn.call(this, e);
+      },
+    },
+  );
+
+  /**
+   * Process elements with the .js-splitbutton class on page load.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches splitButton behaviors.
+   */
+  Drupal.behaviors.splitButton = {
+    attach(context, settings) {
+      const $splitbuttons = $(context)
+        .find('.js-splitbutton')
+        .once('splitbutton');
+
+      if ($splitbuttons.length) {
+        // Initialize all buttons.
+        const il = $splitbuttons.length;
+        for (let i = 0; i < il; i++) {
+          const splitbuttonId = $splitbuttons[i].id;
+          const options = $.extend(
+            {
+              triggerLabel: settings.splitbutton.triggerLabelDefault,
+              triggerLabelVisible: false,
+            },
+            settings.splitbutton.instances[splitbuttonId],
+          );
+
+          SplitButton.splitbuttons.push(
+            new SplitButton($splitbuttons[i], options),
+          );
+        }
+      }
+    },
+  };
+
+  $.extend(
+    Drupal.theme,
+    /** @lends Drupal.theme */ {
+      /**
+       * A toggle is an interactive element often bound to a click handler.
+       *
+       * @param {object} options
+       *   Options object.
+       * @param {string} [options.triggerLabel]
+       *   The button text.
+       *
+       * @return {string}
+       *   A string representing a DOM fragment.
+       */
+      splitbuttonToggle(options) {
+        return `<button type="button" class="button splitbutton__toggle${
+          options.triggerLabelVisible
+            ? ` splitbutton__toggle--with-label`
+            : ` splitbutton__toggle--no-label`
+        }"><span class="splitbutton__toggle-label${
+          options.triggerLabelVisible ? `` : ` visually-hidden`
+        }">${
+          options.triggerLabel
+        }</span> <span class="splitbutton__toggle-arrow"></span></button>`;
+      },
+    },
+  );
+
+  // Expose constructor in the public space.
+  Drupal.SplitButton = SplitButton;
+})(jQuery, Drupal, Popper);
diff --git a/core/misc/splitbutton/splitbutton.js b/core/misc/splitbutton/splitbutton.js
new file mode 100644
index 0000000000..63899f35fd
--- /dev/null
+++ b/core/misc/splitbutton/splitbutton.js
@@ -0,0 +1,247 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function ($, Drupal, Popper) {
+  function SplitButton(splitbutton, options) {
+    var _self = this;
+
+    this.$splitbutton = $(splitbutton);
+
+    $(document).on('ajaxSend.splitbutton', {
+      data: {
+        splitbutton: _self
+      },
+      handler: _self.moveAjaxProgressIndicator
+    });
+
+    this.$list = this.$splitbutton.find('#' + options.listId);
+
+    if (this.$list.length !== 1) {
+      return;
+    }
+
+    this.expanded = false;
+
+    this.$actions = this.$list.children();
+
+    this.$toggle = $(Drupal.theme('splitbuttonToggle', options)).addClass('js-splitbutton-toggle').attr('aria-haspopup', 'true').attr('aria-controls', options.listId).attr('id', options.buttonId).on({
+      click: {
+        data: _self,
+        handler: _self.toggleClickHandler
+      },
+      keydown: {
+        data: _self,
+        handler: _self.toggleKeyHandler
+      }
+    });
+
+    this.$list.on('keydown', this, this.listKeyHandler);
+
+    if (this.$splitbutton.find('.js-splitbutton-toggle-placeholder').length === 1) {
+      this.$splitbutton.find('.js-splitbutton-toggle-placeholder').replaceWith(this.$toggle);
+    } else {
+      this.$list.before(this.$toggle);
+    }
+
+    this.$splitbutton.on({
+      'mouseleave.splitbutton': $.proxy(this.hoverOut, this),
+
+      'mouseenter.splitbutton': $.proxy(this.hoverIn, this),
+
+      'focusout.splitbutton': $.proxy(this.focusOut, this),
+
+      'focusin.splitbutton': $.proxy(this.focusIn, this)
+    });
+
+    this.$list.find('.js-splitbutton-action-secondary').attr('tabindex', -1);
+  }
+
+  $.extend(SplitButton, {
+    splitbuttons: []
+  });
+
+  $.extend(SplitButton.prototype, {
+    moveAjaxProgressIndicator: function moveAjaxProgressIndicator(event) {
+      var $splitbutton = event.data.splitbutton.$splitbutton;
+      var $throbber = $(Drupal.theme.ajaxProgressThrobber());
+      var $progressBar = Drupal.theme.ajaxProgressBar($('<span></span>'));
+
+      [$throbber[0], $progressBar[0]].forEach(function (progressNode) {
+        var classSelector = progressNode.className ? '[class="' + progressNode.className + '"]' : '';
+        var progressSelector = progressNode.tagName + classSelector;
+
+        if (classSelector) {
+          var $progressElementInDocument = $(document).find(progressSelector);
+          var $progressElementInSplitbutton = $splitbutton.find(progressSelector);
+
+          if ($progressElementInSplitbutton.length === 1 && $progressElementInDocument.length === 1) {
+            $splitbutton.after($progressElementInSplitbutton);
+          }
+        }
+      });
+    },
+    toggle: function toggle(show) {
+      var isBool = typeof show === 'boolean';
+      show = isBool ? show : !this.expanded;
+      this.expanded = show;
+      this.$list.toggleClass('open', show);
+      this.$splitbutton.toggleClass('open', show);
+
+      if (show) {
+        this.$toggle.attr('aria-expanded', 'true');
+        this.$list.find('.js-splitbutton-action-secondary').removeAttr('tabindex');
+
+        if (this.popper) {
+          this.popper.update();
+        } else {
+          var edge = document.documentElement.dir === 'rtl' ? 'start' : 'end';
+          this.popper = new Popper(this.$splitbutton, this.$list, {
+            placement: 'bottom-' + edge,
+            modifiers: {
+              flip: {
+                enabled: false
+              },
+              computeStyle: {
+                gpuAcceleration: false
+              }
+            }
+          });
+        }
+      } else {
+        this.$toggle.removeAttr('aria-expanded');
+        this.$list.find('.js-splitbutton-action-secondary').attr('tabindex', -1);
+      }
+
+      return this;
+    },
+    focusAction: function focusAction(direction) {
+      var $listItemFocused = this.$actions.has(':focus');
+      var $listItemFirst = this.$actions.first();
+      var $listItemLast = this.$actions.last();
+      var $nextlistItem = $listItemFocused.next().length ? $listItemFocused.next() : $listItemLast;
+      var $prevlistItem = $listItemFocused.prev().length ? $listItemFocused.prev() : $listItemFirst;
+
+      this.toggle(true);
+
+      switch (direction) {
+        case 'next':
+          $nextlistItem.find(':focusable').first().trigger('focus');
+          break;
+
+        case 'previous':
+          $prevlistItem.find(':focusable').first().trigger('focus');
+          break;
+
+        case 'first':
+          $listItemFirst.find(':focusable').first().trigger('focus');
+          break;
+
+        case 'last':
+          $listItemLast.find(':focusable').first().trigger('focus');
+          break;
+      }
+    },
+    toggleClickHandler: function toggleClickHandler(event) {
+      event.data.toggle();
+      event.preventDefault();
+    },
+    toggleKeyHandler: function toggleKeyHandler(event) {
+      switch (event.key) {
+        case 'ArrowUp':
+          event.data.focusAction('last');
+          event.preventDefault();
+          break;
+
+        case ' ':
+        case 'Enter':
+          event.data.toggle();
+          event.preventDefault();
+          break;
+
+        case 'ArrowDown':
+          event.data.focusAction('first');
+          event.preventDefault();
+          break;
+      }
+    },
+    listKeyHandler: function listKeyHandler(event) {
+      switch (event.key) {
+        case 'ArrowUp':
+          event.data.focusAction('previous');
+          event.preventDefault();
+          break;
+
+        case 'ArrowDown':
+          event.data.focusAction('next');
+          event.preventDefault();
+          break;
+
+        case 'Home':
+          event.data.focusAction('first');
+          event.preventDefault();
+          break;
+
+        case 'End':
+          event.data.focusAction('last');
+          event.preventDefault();
+          break;
+
+        case 'Escape':
+          event.data.toggle(false).$toggle.trigger('focus');
+          event.preventDefault();
+          break;
+      }
+    },
+    hoverIn: function hoverIn() {
+      if (this.timerID) {
+        window.clearTimeout(this.timerID);
+      }
+    },
+    hoverOut: function hoverOut() {
+      this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
+    },
+    open: function open() {
+      this.toggle(true);
+    },
+    close: function close() {
+      this.toggle(false);
+    },
+    focusOut: function focusOut(e) {
+      this.hoverOut.call(this, e);
+    },
+    focusIn: function focusIn(e) {
+      this.hoverIn.call(this, e);
+    }
+  });
+
+  Drupal.behaviors.splitButton = {
+    attach: function attach(context, settings) {
+      var $splitbuttons = $(context).find('.js-splitbutton').once('splitbutton');
+
+      if ($splitbuttons.length) {
+        var il = $splitbuttons.length;
+        for (var i = 0; i < il; i++) {
+          var splitbuttonId = $splitbuttons[i].id;
+          var options = $.extend({
+            triggerLabel: settings.splitbutton.triggerLabelDefault,
+            triggerLabelVisible: false
+          }, settings.splitbutton.instances[splitbuttonId]);
+
+          SplitButton.splitbuttons.push(new SplitButton($splitbuttons[i], options));
+        }
+      }
+    }
+  };
+
+  $.extend(Drupal.theme, {
+    splitbuttonToggle: function splitbuttonToggle(options) {
+      return '<button type="button" class="button splitbutton__toggle' + (options.triggerLabelVisible ? ' splitbutton__toggle--with-label' : ' splitbutton__toggle--no-label') + '"><span class="splitbutton__toggle-label' + (options.triggerLabelVisible ? '' : ' visually-hidden') + '">' + options.triggerLabel + '</span> <span class="splitbutton__toggle-arrow"></span></button>';
+    }
+  });
+
+  Drupal.SplitButton = SplitButton;
+})(jQuery, Drupal, Popper);
\ No newline at end of file
diff --git a/core/modules/aggregator/src/Controller/AggregatorController.php b/core/modules/aggregator/src/Controller/AggregatorController.php
index 5beb15441c..9ce2cf913e 100644
--- a/core/modules/aggregator/src/Controller/AggregatorController.php
+++ b/core/modules/aggregator/src/Controller/AggregatorController.php
@@ -149,8 +149,8 @@ public function adminOverview() {
       ];
       $row[] = [
         'data' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
       $rows[] = $row;
diff --git a/core/modules/ban/src/Form/BanAdmin.php b/core/modules/ban/src/Form/BanAdmin.php
index d71be8d402..dccb78216c 100644
--- a/core/modules/ban/src/Form/BanAdmin.php
+++ b/core/modules/ban/src/Form/BanAdmin.php
@@ -67,8 +67,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $default_
       ];
       $row[] = [
         'data' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
       $rows[] = $row;
diff --git a/core/modules/block/src/Controller/BlockLibraryController.php b/core/modules/block/src/Controller/BlockLibraryController.php
index cf5f20a0ba..bf9f7ea809 100644
--- a/core/modules/block/src/Controller/BlockLibraryController.php
+++ b/core/modules/block/src/Controller/BlockLibraryController.php
@@ -145,8 +145,8 @@ public function listBlocks(Request $request, $theme) {
         $links['add']['query']['weight'] = $weight;
       }
       $row['operations']['data'] = [
-        '#type' => 'operations',
-        '#links' => $links,
+        '#type' => 'splitbutton_operations',
+        '#items' => $links,
       ];
       $rows[] = $row;
     }
diff --git a/core/modules/book/src/Controller/BookController.php b/core/modules/book/src/Controller/BookController.php
index bb09ae9719..ac2f9ed402 100644
--- a/core/modules/book/src/Controller/BookController.php
+++ b/core/modules/book/src/Controller/BookController.php
@@ -94,8 +94,8 @@ public function adminOverview() {
       ];
       $row[] = [
         'data' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
       $rows[] = $row;
diff --git a/core/modules/book/src/Form/BookAdminEditForm.php b/core/modules/book/src/Form/BookAdminEditForm.php
index d5d29c1cc8..b6dbb8fe1c 100644
--- a/core/modules/book/src/Form/BookAdminEditForm.php
+++ b/core/modules/book/src/Form/BookAdminEditForm.php
@@ -268,20 +268,20 @@ protected function bookAdminTableTree(array $tree, array &$form) {
       ];
 
       $form[$id]['operations'] = [
-        '#type' => 'operations',
+        '#type' => 'splitbutton_operations',
       ];
-      $form[$id]['operations']['#links']['view'] = [
+      $form[$id]['operations']['#items']['view'] = [
         'title' => $this->t('View'),
         'url' => new Url('entity.node.canonical', ['node' => $nid]),
       ];
 
       if ($access) {
-        $form[$id]['operations']['#links']['edit'] = [
+        $form[$id]['operations']['#items']['edit'] = [
           'title' => $this->t('Edit'),
           'url' => new Url('entity.node.edit_form', ['node' => $nid]),
           'query' => $destination,
         ];
-        $form[$id]['operations']['#links']['delete'] = [
+        $form[$id]['operations']['#items']['delete'] = [
           'title' => $this->t('Delete'),
           'url' => new Url('entity.node.delete_form', ['node' => $nid]),
           'query' => $destination,
diff --git a/core/modules/book/tests/src/Functional/BookTest.php b/core/modules/book/tests/src/Functional/BookTest.php
index e1e81955d2..6ec9655c16 100644
--- a/core/modules/book/tests/src/Functional/BookTest.php
+++ b/core/modules/book/tests/src/Functional/BookTest.php
@@ -510,7 +510,7 @@ public function testAdminBookNodeListing() {
     $this->drupalGet('admin/structure/book/' . $this->book->id());
     $this->assertText($this->book->label(), 'The book title is displayed on the administrative book listing page.');
 
-    $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a');
+    $elements = $this->xpath("//table//div[contains(concat(' ', normalize-space(@class), ' '), ' splitbutton ')]//a");
     $this->assertEqual($elements[0]->getText(), 'View', 'View link is found from the list.');
   }
 
diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php
index 42c76e485b..ef371174e3 100644
--- a/core/modules/comment/src/Form/CommentAdminOverview.php
+++ b/core/modules/comment/src/Form/CommentAdminOverview.php
@@ -233,8 +233,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $type = '
         ];
       }
       $options[$comment->id()]['operations']['data'] = [
-        '#type' => 'operations',
-        '#links' => $links,
+        '#type' => 'splitbutton_operations',
+        '#items' => $links,
       ];
     }
 
diff --git a/core/modules/config/src/Form/ConfigSync.php b/core/modules/config/src/Form/ConfigSync.php
index 71fb3681f1..3f10ef05df 100644
--- a/core/modules/config/src/Form/ConfigSync.php
+++ b/core/modules/config/src/Form/ConfigSync.php
@@ -333,8 +333,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
             'name' => $config_name,
             'operations' => [
               'data' => [
-                '#type' => 'operations',
-                '#links' => $links,
+                '#type' => 'splitbutton_operations',
+                '#items' => $links,
               ],
             ],
           ];
diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationController.php b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
index 8c9dc480e8..1bc5c58305 100644
--- a/core/modules/config_translation/src/Controller/ConfigTranslationController.php
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
@@ -243,8 +243,8 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
       ];
 
       $page['languages'][$langcode]['operations'] = [
-        '#type' => 'operations',
-        '#links' => $operations,
+        '#type' => 'splitbutton_operations',
+        '#items' => $operations,
         // Even if the mapper contains multiple language codes, the source
         // configuration can still be edited.
         '#access' => ($langcode == $original_langcode) || $operations_access,
diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php b/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
index 4e510aaf38..3db092f105 100644
--- a/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
@@ -121,8 +121,8 @@ protected function buildOperations(ConfigMapperInterface $mapper) {
     $operations = $mapper->getOperations();
     uasort($operations, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
     $build = [
-      '#type' => 'operations',
-      '#links' => $operations,
+      '#type' => 'splitbutton_operations',
+      '#items' => $operations,
     ];
     return $build;
   }
diff --git a/core/modules/content_moderation/src/Form/ContentModerationConfigureForm.php b/core/modules/content_moderation/src/Form/ContentModerationConfigureForm.php
index f43451ec63..578a02c26c 100644
--- a/core/modules/content_moderation/src/Form/ContentModerationConfigureForm.php
+++ b/core/modules/content_moderation/src/Form/ContentModerationConfigureForm.php
@@ -112,8 +112,8 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
           ],
         ],
         'operations' => [
-          '#type' => 'operations',
-          '#links' => [
+          '#type' => 'splitbutton_operations',
+          '#items' => [
             'select' => [
               'title' => $this->t('Select'),
               'url' => Url::fromRoute('content_moderation.workflow_type_edit_form', ['workflow' => $workflow->id(), 'entity_type_id' => $entity_type->id()]),
diff --git a/core/modules/content_translation/src/Controller/ContentTranslationController.php b/core/modules/content_translation/src/Controller/ContentTranslationController.php
index 5d48cc0533..dfe8951bc7 100644
--- a/core/modules/content_translation/src/Controller/ContentTranslationController.php
+++ b/core/modules/content_translation/src/Controller/ContentTranslationController.php
@@ -176,12 +176,12 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
           ->setRouteParameter('language', $language->getId());
         $operations = [
           'data' => [
-            '#type' => 'operations',
-            '#links' => [],
+            '#type' => 'splitbutton_operations',
+            '#itemss' => [],
           ],
         ];
 
-        $links = &$operations['data']['#links'];
+        $links = &$operations['data']['#items'];
         if (array_key_exists($langcode, $translations)) {
           // Existing translation in the translation set: display status.
           $translation = $entity->getTranslation($langcode);
diff --git a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
index 5e7954086f..9617128e76 100644
--- a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
@@ -226,7 +226,7 @@ protected function doTestTranslationOverview() {
         $elements = $this->xpath('//table//a[@href=:href]', [':href' => $view_url]);
         $this->assertEqual($elements[0]->getText(), $entity->getTranslation($langcode)->label(), new FormattableMarkup('Label correctly shown for %language translation.', ['%language' => $langcode]));
         $edit_path = $entity->toUrl('edit-form', ['language' => $language])->toString();
-        $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', [':href' => $edit_path]);
+        $elements = $this->xpath("//table//div[contains(concat(' ', normalize-space(@class), ' '), ' splitbutton ')]//a[@href=:href]", [':href' => $edit_path]);
         $this->assertEqual($elements[0]->getText(), t('Edit'), new FormattableMarkup('Edit link correct for %language translation.', ['%language' => $langcode]));
       }
     }
diff --git a/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php b/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php
index c9dcd3490c..1fbd593ebd 100644
--- a/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php
+++ b/core/modules/field_ui/tests/src/Functional/ManageFieldsFunctionalTest.php
@@ -156,7 +156,7 @@ public function manageFieldsPage($type = '') {
     // Assert entity operations for all fields.
     $number_of_links = 3;
     $number_of_links_found = 0;
-    $operation_links = $this->xpath('//ul[@class = "dropbutton"]/li/a');
+    $operation_links = $this->xpath("//div[contains(concat(' ', normalize-space(@class), ' '), ' splitbutton ')]//a");
     $url = base_path() . "admin/structure/types/manage/$type/fields/node.$type.body";
 
     foreach ($operation_links as $link) {
diff --git a/core/modules/forum/src/Form/Overview.php b/core/modules/forum/src/Form/Overview.php
index 2158170da8..44718307f2 100644
--- a/core/modules/forum/src/Form/Overview.php
+++ b/core/modules/forum/src/Form/Overview.php
@@ -54,8 +54,8 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
 
         // Re-create the operations column and add only the edit link.
         $form['terms'][$key]['operations'] = [
-          '#type' => 'operations',
-          '#links' => [
+          '#type' => 'splitbutton_operations',
+          '#items' => [
             'edit' => [
               'title' => $title,
               'url' => $url,
diff --git a/core/modules/image/src/Form/ImageStyleEditForm.php b/core/modules/image/src/Form/ImageStyleEditForm.php
index f33c20b870..19162744ae 100644
--- a/core/modules/image/src/Form/ImageStyleEditForm.php
+++ b/core/modules/image/src/Form/ImageStyleEditForm.php
@@ -137,8 +137,8 @@ public function form(array $form, FormStateInterface $form_state) {
         ]),
       ];
       $form['effects'][$key]['operations'] = [
-        '#type' => 'operations',
-        '#links' => $links,
+        '#type' => 'splitbutton_operations',
+        '#items' => $links,
       ];
     }
 
diff --git a/core/modules/language/src/Form/NegotiationBrowserForm.php b/core/modules/language/src/Form/NegotiationBrowserForm.php
index 1ffd1a2c5c..5ad755a866 100644
--- a/core/modules/language/src/Form/NegotiationBrowserForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
@@ -115,8 +115,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       ];
       // Operations column.
       $form['mappings'][$browser_langcode]['operations'] = [
-        '#type' => 'operations',
-        '#links' => [],
+        '#type' => 'splitbutton_operations',
+        '#items' => [],
       ];
       $form['mappings'][$browser_langcode]['operations']['#links']['delete'] = [
         'title' => $this->t('Delete'),
diff --git a/core/modules/language/src/Form/NegotiationConfigureForm.php b/core/modules/language/src/Form/NegotiationConfigureForm.php
index 0679a563d2..9ac3f400d4 100644
--- a/core/modules/language/src/Form/NegotiationConfigureForm.php
+++ b/core/modules/language/src/Form/NegotiationConfigureForm.php
@@ -308,8 +308,8 @@ protected function configureFormTable(array &$form, $type) {
           $table_form['#show_operations'] = TRUE;
         }
         $table_form['operation'][$method_id] = [
-         '#type' => 'operations',
-         '#links' => $config_op,
+         '#type' => 'splitbutton_operations',
+         '#items' => $config_op,
         ];
       }
     }
diff --git a/core/modules/menu_ui/src/MenuForm.php b/core/modules/menu_ui/src/MenuForm.php
index ccedad3133..6b853e324b 100644
--- a/core/modules/menu_ui/src/MenuForm.php
+++ b/core/modules/menu_ui/src/MenuForm.php
@@ -469,8 +469,8 @@ protected function buildOverviewTreeForm($tree, $delta) {
           ];
         }
         $form[$id]['operations'] = [
-          '#type' => 'operations',
-          '#links' => $operations,
+          '#type' => 'splitbutton_operations',
+          '#items' => $operations,
         ];
       }
 
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php
index 385d2bc5ac..c560dcc427 100644
--- a/core/modules/node/src/Controller/NodeController.php
+++ b/core/modules/node/src/Controller/NodeController.php
@@ -274,8 +274,8 @@ public function revisionOverview(NodeInterface $node) {
 
           $row[] = [
             'data' => [
-              '#type' => 'operations',
-              '#links' => $links,
+              '#type' => 'splitbutton_operations',
+              '#items' => $links,
             ],
           ];
 
diff --git a/core/modules/shortcut/src/Form/SetCustomize.php b/core/modules/shortcut/src/Form/SetCustomize.php
index 6f86a0e2a0..292f353af4 100644
--- a/core/modules/shortcut/src/Form/SetCustomize.php
+++ b/core/modules/shortcut/src/Form/SetCustomize.php
@@ -75,8 +75,8 @@ public function form(array $form, FormStateInterface $form_state) {
         'url' => $shortcut->toUrl('delete-form'),
       ];
       $form['shortcuts']['links'][$id]['operations'] = [
-        '#type' => 'operations',
-        '#links' => $links,
+        '#type' => 'splitbutton_operations',
+        '#items' => $links,
         '#access' => $url->access(),
       ];
     }
diff --git a/core/modules/system/templates/splitbutton.html.twig b/core/modules/system/templates/splitbutton.html.twig
new file mode 100644
index 0000000000..0811b6d727
--- /dev/null
+++ b/core/modules/system/templates/splitbutton.html.twig
@@ -0,0 +1,65 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a splitbutton used to wrap child elements.
+ *
+ * Used for grouped buttons and link items.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - content_attributes: HTML attributes for the list element.
+ * - item_attributes: HTML attributes for the list item.
+ * - main_items: The uncollapsed splitbutton elements.
+ * - items: Further child elements of the splitbutton.
+ * - multiple: Whether the splitbutton has subitems.
+ * - trigger_label: The label of the toggle.
+ * - trigger_label_visible: Whether the label of the toggle should be visible.
+ *
+ * @see template_preprocess_splitbutton()
+ */
+#}
+{% if main_items or items %}
+{%
+  set classes = [
+    'splitbutton',
+    multiple ? 'splitbutton--multiple' : 'splitbutton--single'
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {% if not multiple %}
+    <div class="splitbutton__main-items">
+      {% for main_item in main_items %}
+        {{ main_item.value }}
+      {% endfor %}
+    </div>
+  {% else %}
+    {%
+      set trigger_placeholder_classes = [
+        'button',
+        'splitbutton__toggle',
+        trigger_label_visible ? 'splitbutton__toggle--with-label' : 'splitbutton__toggle--no-label'
+      ]
+    %}
+    {%
+      set trigger_placeholder_attributes = create_attribute({'class': trigger_placeholder_classes})
+    %}
+    <div class="splitbutton__main-items">
+      {% for main_item in main_items %}
+        {{ main_item.value }}
+      {% endfor %}
+      <span{{ trigger_placeholder_attributes.addClass('js-splitbutton-toggle-placeholder') }}>
+        <span class="splitbutton__toggle-label{{ trigger_label_visible ? '' : ' visually-hidden' }}">{{ trigger_label }}</span>
+        <span class="splitbutton__toggle-arrow invisible"></span>
+      </span>
+    </div>
+
+    {% if items %}
+    <ul{{ content_attributes.addClass('splitbutton__list') }}>
+      {% for item in items %}
+        <li{{ item.attributes.addClass('splitbutton__list-item') }}>{{ item.value }}</li>
+      {% endfor %}
+    </ul>
+    {% endif %}
+  {% endif %}
+</div>
+{% endif %}
diff --git a/core/modules/taxonomy/src/Form/OverviewTerms.php b/core/modules/taxonomy/src/Form/OverviewTerms.php
index 502900b87d..224983b4cb 100644
--- a/core/modules/taxonomy/src/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/src/Form/OverviewTerms.php
@@ -420,8 +420,8 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
 
       if ($operations = $this->termListBuilder->getOperations($term)) {
         $form['terms'][$key]['operations'] = [
-          '#type' => 'operations',
-          '#links' => $operations,
+          '#type' => 'splitbutton_operations',
+          '#items' => $operations,
         ];
       }
 
diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php
index f8d8ed6301..53d7ecb092 100644
--- a/core/modules/views/src/EntityViewsData.php
+++ b/core/modules/views/src/EntityViewsData.php
@@ -217,6 +217,27 @@ public function getViewsData() {
       }
     }
 
+    // Entity types must implement a list_builder in order to use Views'
+    // entity splitbutton operations field.
+    if ($this->entityType->hasListBuilderClass()) {
+      $data[$base_table]['splitbutton_operations'] = [
+        'field' => [
+          'title' => $this->t('Splitbutton operations links'),
+          'help' => $this->t('Provides splitbutton to perform entity operations.'),
+          'id' => 'entity_splitbutton_operations',
+        ],
+      ];
+      if ($revision_table) {
+        $data[$revision_table]['splitbutton_operations'] = [
+          'field' => [
+            'title' => $this->t('Splitbutton operation links'),
+            'help' => $this->t('Provides splitbutton to perform entity operations.'),
+            'id' => 'entity_splitbutton_operations',
+          ],
+        ];
+      }
+    }
+
     if ($this->entityType->hasViewBuilderClass()) {
       $data[$base_table]['rendered_entity'] = [
         'field' => [
diff --git a/core/modules/views/src/Plugin/views/field/EntitySplitbuttonOperations.php b/core/modules/views/src/Plugin/views/field/EntitySplitbuttonOperations.php
new file mode 100644
index 0000000000..6c3a36cc9b
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/EntitySplitbuttonOperations.php
@@ -0,0 +1,223 @@
+<?php
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Routing\RedirectDestinationTrait;
+use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
+use Drupal\views\ResultRow;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Renders all operations links for an entity.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("entity_splitbutton_operations")
+ */
+class EntitySplitbuttonOperations extends FieldPluginBase {
+
+  use EntityTranslationRenderTrait;
+  use RedirectDestinationTrait;
+  use DeprecatedServicePropertyTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity repository service.
+   *
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface
+   */
+  protected $entityRepository;
+
+  /**
+   * The entity display repository.
+   *
+   * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
+   */
+  protected $entityDisplayRepository;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface
+   */
+  protected $languageManager;
+
+  /**
+   * Constructs a new EntityOperations object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity manager.
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The language manager.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, EntityRepositoryInterface $entity_repository = NULL) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityTypeManager = $entity_type_manager;
+    $this->languageManager = $language_manager;
+
+    if (!$entity_repository) {
+      @trigger_error('Calling EntityOperations::__construct() with the $entity_repository argument is supported in drupal:8.7.0 and will be required before drupal:9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
+      $entity_repository = \Drupal::service('entity.repository');
+    }
+    $this->entityRepository = $entity_repository;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('language_manager'),
+      $container->get('entity.repository')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function usesGroupBy() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defineOptions() {
+    $options = parent::defineOptions();
+
+    $options['destination'] = [
+      'default' => FALSE,
+    ];
+
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['destination'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Include destination'),
+      '#description' => $this->t('Enforce a <code>destination</code> parameter in the link to return the user to the original view upon completing the link action. Most operations include a destination by default and this setting is no longer needed.'),
+      '#default_value' => $this->options['destination'],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    $entity = $this->getEntityTranslation($this->getEntity($values), $values);
+    $operations = $this->entityTypeManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
+    if ($this->options['destination']) {
+      foreach ($operations as &$operation) {
+        if (!isset($operation['query'])) {
+          $operation['query'] = [];
+        }
+        $operation['query'] += $this->getDestinationArray();
+      }
+    }
+    $build = [
+      '#type' => 'splitbutton_operations',
+      '#items' => $operations,
+    ];
+
+    return $build;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    // We purposefully do not call parent::query() because we do not want the
+    // default query behavior for Views fields. Instead, let the entity
+    // translation renderer provide the correct query behavior.
+    if ($this->languageManager->isMultilingual()) {
+      $this->getEntityTranslationRenderer()->query($this->query, $this->relationship);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityTypeId() {
+    return $this->getEntityType();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityManager() {
+    // This relies on DeprecatedServicePropertyTrait to trigger a deprecation
+    // message in case it is accessed.
+    return $this->entityManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityTypeManager() {
+    return $this->entityTypeManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityRepository() {
+    return $this->entityRepository;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getLanguageManager() {
+    return $this->languageManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getView() {
+    return $this->view;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clickSortable() {
+    return FALSE;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/field/Splitbutton.php b/core/modules/views/src/Plugin/views/field/Splitbutton.php
new file mode 100644
index 0000000000..81188f5413
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/Splitbutton.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\views\ResultRow;
+
+/**
+ * Provides a handler that renders links as splitbutton.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("splitbutton")
+ */
+class Splitbutton extends Links {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    $links = $this->getLinks();
+
+    if (!empty($links)) {
+      return $links + [
+        '#type' => 'splitbutton',
+      ];
+    }
+    else {
+      return '';
+    }
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/EntitySplitbuttonOperationsUnitTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/EntitySplitbuttonOperationsUnitTest.php
new file mode 100644
index 0000000000..e2dc926004
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/EntitySplitbuttonOperationsUnitTest.php
@@ -0,0 +1,177 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\field\EntitySplitbuttonOperations;
+use Drupal\views\ResultRow;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\EntitySplitbuttonOperations
+ * @group Views
+ */
+class EntitySplitbuttonOperationsUnitTest extends UnitTestCase {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity repository.
+   *
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $entityRepository;
+
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject
+   */
+  protected $languageManager;
+
+  /**
+   * The plugin under test.
+   *
+   * @var \Drupal\views\Plugin\views\field\EntitySplitbuttonOperations
+   */
+  protected $plugin;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @covers ::__construct
+   */
+  protected function setUp() {
+    $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
+    $this->entityRepository = $this->createMock(EntityRepositoryInterface::class);
+    $this->languageManager = $this->createMock('\Drupal\Core\Language\LanguageManagerInterface');
+
+    $configuration = [];
+    $plugin_id = $this->randomMachineName();
+    $plugin_definition = [
+      'title' => $this->randomMachineName(),
+    ];
+    $this->plugin = new EntitySplitbuttonOperations($configuration, $plugin_id, $plugin_definition, $this->entityTypeManager, $this->languageManager, $this->entityRepository);
+
+    $redirect_service = $this->createMock('Drupal\Core\Routing\RedirectDestinationInterface');
+    $redirect_service->expects($this->any())
+      ->method('getAsArray')
+      ->willReturn(['destination' => 'foobar']);
+    $this->plugin->setRedirectDestination($redirect_service);
+
+    $view = $this->getMockBuilder('\Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $display = $this->getMockBuilder('\Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $view->display_handler = $display;
+    $this->plugin->init($view, $display);
+  }
+
+  /**
+   * @covers ::usesGroupBy
+   */
+  public function testUsesGroupBy() {
+    $this->assertFalse($this->plugin->usesGroupBy());
+  }
+
+  /**
+   * @covers ::defineOptions
+   */
+  public function testDefineOptions() {
+    $options = $this->plugin->defineOptions();
+    $this->assertInternalType('array', $options);
+    $this->assertArrayHasKey('destination', $options);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRenderWithDestination() {
+    $entity_type_id = $this->randomMachineName();
+    $entity = $this->getMockBuilder('\Drupal\user\Entity\Role')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->any())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue($entity_type_id));
+
+    $operations = [
+      'foo' => [
+        'title' => $this->randomMachineName(),
+      ],
+    ];
+    $list_builder = $this->createMock('\Drupal\Core\Entity\EntityListBuilderInterface');
+    $list_builder->expects($this->once())
+      ->method('getOperations')
+      ->with($entity)
+      ->will($this->returnValue($operations));
+
+    $this->entityTypeManager->expects($this->once())
+      ->method('getListBuilder')
+      ->with($entity_type_id)
+      ->will($this->returnValue($list_builder));
+
+    $this->plugin->options['destination'] = TRUE;
+
+    $result = new ResultRow();
+    $result->_entity = $entity;
+
+    $expected_build = [
+      '#type' => 'splitbutton_operations',
+      '#items' => $operations,
+    ];
+    $expected_build['foo']['query'] = ['destination' => 'foobar'];
+    $build = $this->plugin->render($result);
+    $this->assertSame($expected_build, $build);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRenderWithoutDestination() {
+    $entity_type_id = $this->randomMachineName();
+    $entity = $this->getMockBuilder('\Drupal\user\Entity\Role')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->any())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue($entity_type_id));
+
+    $operations = [
+      'foo' => [
+        'title' => $this->randomMachineName(),
+      ],
+    ];
+    $list_builder = $this->createMock('\Drupal\Core\Entity\EntityListBuilderInterface');
+    $list_builder->expects($this->once())
+      ->method('getOperations')
+      ->with($entity)
+      ->will($this->returnValue($operations));
+
+    $this->entityTypeManager->expects($this->once())
+      ->method('getListBuilder')
+      ->with($entity_type_id)
+      ->will($this->returnValue($list_builder));
+
+    $this->plugin->options['destination'] = FALSE;
+
+    $result = new ResultRow();
+    $result->_entity = $entity;
+
+    $expected_build = [
+      '#type' => 'splitbutton_operations',
+      '#items' => $operations,
+    ];
+    $build = $this->plugin->render($result);
+    $this->assertSame($expected_build, $build);
+  }
+
+}
diff --git a/core/modules/views_ui/css/views_ui.admin.css b/core/modules/views_ui/css/views_ui.admin.css
index 2507d30657..de79c5a65c 100644
--- a/core/modules/views_ui/css/views_ui.admin.css
+++ b/core/modules/views_ui/css/views_ui.admin.css
@@ -4,7 +4,6 @@
  * declarations. For example: display, position, float, clear, and overflow.
  */
 
-.views-admin ul,
 .views-admin menu,
 .views-admin dir {
   padding: 0;
@@ -100,10 +99,6 @@
   border-right: 1px solid #bfbfbf;
   border-left: 0 none;
 }
-.views-displays .tabs .open > a {
-  position: relative;
-  z-index: 51;
-}
 .views-displays .tabs .views-display-deleted-link {
   text-decoration: line-through;
 }
@@ -120,23 +115,6 @@
 .views-display-tab .details-wrapper > .views-ui-display-tab-bucket .actions {
   opacity: 1;
 }
-.views-displays .tabs .add {
-  position: relative;
-}
-.views-displays .tabs .action-list {
-  position: absolute;
-  z-index: 50;
-  top: 23px;
-  left: 0; /* LTR */
-  margin: 0;
-}
-[dir="rtl"] .views-displays .tabs .action-list {
-  right: 0;
-  left: auto;
-}
-.views-displays .tabs .action-list li {
-  display: block;
-}
 .views-display-columns .details-wrapper {
   padding: 0;
 }
@@ -203,6 +181,3 @@ html.js .js-only {
 html.js span.js-only {
   display: inline;
 }
-.js .views-edit-view .dropbutton-wrapper {
-  width: auto;
-}
diff --git a/core/modules/views_ui/css/views_ui.admin.theme.css b/core/modules/views_ui/css/views_ui.admin.theme.css
index a1e7cc287b..10c27ccf26 100644
--- a/core/modules/views_ui/css/views_ui.admin.theme.css
+++ b/core/modules/views_ui/css/views_ui.admin.theme.css
@@ -104,9 +104,6 @@
 .views-displays .tabs a:hover > .icon.add {
   background-position: center -25px;
 }
-.views-displays .tabs .open a:hover > .icon.add {
-  background-position: center 3px;
-}
 details.box-padding {
   border: none;
 }
@@ -295,24 +292,20 @@ td.group-title {
 }
 .views-display-top {
   position: relative;
-  padding: 8px 8px 3px;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  padding: 6px 8px;
   border-bottom: 1px solid #ccc;
   background-color: #e1e2dc;
 }
-.views-display-top .tabs {
-  margin-right: 18em; /* LTR */
-}
-[dir="rtl"] .views-display-top .tabs {
-  margin-right: 0;
-  margin-left: 18em;
-}
 .views-display-top .tabs > li {
-  margin-right: 6px; /* LTR */
+  margin: 2px 5px 2px 6px; /* LTR */
   padding-left: 0; /* LTR */
 }
 [dir="rtl"] .views-display-top .tabs > li {
-  margin-right: 0.3em;
-  margin-left: 6px;
+  margin-right: 6px;
+  margin-left: 5px;
   padding-right: 0;
 }
 .views-display-top .tabs > li:last-child {
@@ -322,6 +315,14 @@ td.group-title {
   margin-right: 0.3em;
   margin-left: 0;
 }
+.views-ui-views-extra-actions {
+  margin: 2px 5px 2px 6px;
+}
+[dir="rtl"] .views-ui-views-extra-actions {
+  margin-right: 6px;
+  margin-left: 5px;
+}
+
 .form-edit .form-actions {
   margin-top: 0;
   padding: 8px 12px;
@@ -331,12 +332,8 @@ td.group-title {
   background-color: #e1e2dc;
 }
 .views-displays .tabs.secondary {
-  margin-right: 200px; /* LTR */
-  border: 0;
-}
-[dir="rtl"] .views-displays .tabs.secondary {
-  margin-right: 0;
-  margin-left: 200px;
+  flex-grow: 1;
+  list-style: none;
 }
 .views-displays .tabs.secondary li,
 .views-displays .tabs.secondary li.is-active {
@@ -345,16 +342,6 @@ td.group-title {
   border: 0;
   background: transparent;
 }
-.views-displays .tabs li.add ul.action-list li {
-  margin: 0;
-}
-.views-displays .tabs.secondary li {
-  margin: 0 5px 5px 6px; /* LTR */
-}
-[dir="rtl"] .views-displays .tabs.secondary li {
-  margin-right: 6px;
-  margin-left: 5px;
-}
 .views-displays .tabs.secondary .tabs__tab + .tabs__tab {
   border-top: 0;
 }
@@ -365,11 +352,13 @@ td.group-title {
 [dir="rtl"] .views-displays .tabs li.tabs__tab:hover {
   padding-right: 0;
 }
-.views-displays .tabs.secondary a {
+.views-displays .tabs.secondary a,
+.views-ui-views-display-add-actions .splitbutton__toggle.splitbutton__toggle {
   display: inline-block;
   padding: 3px 7px;
   border: 1px solid #cbcbcb;
   border-radius: 7px;
+  font-family: inherit;
   font-size: small;
   line-height: 1.3333;
 }
@@ -387,60 +376,23 @@ td.group-title {
 .views-displays .tabs.secondary li a {
   background-color: #fff;
 }
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:focus {
+  text-decoration: underline;
+}
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:hover {
+  color: #000;
+  background: #fff;
+}
 .views-displays .tabs li a:hover,
 .views-displays .tabs li.is-active a,
-.views-displays .tabs li.is-active a.is-active {
+.views-displays .tabs li.is-active a.is-active,
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:hover {
   color: #fff;
   background-color: #555;
 }
-.views-displays .tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-.views-displays .tabs .action-list input.form-submit:hover {
-  box-shadow: none;
-}
-.views-displays .tabs .action-list li:hover {
-  background-color: #ddd;
-}
 .edit-display-settings {
   margin: 12px 12px 0 12px;
 }
-.edit-display-settings-top.views-ui-display-tab-bucket {
-  position: relative;
-  margin: 0 0 15px 0;
-  padding-top: 4px;
-  padding-bottom: 4px;
-  border: 1px solid #f3f3f3;
-  line-height: 20px;
-}
 .views-display-column {
   border: 1px solid #f3f3f3;
 }
@@ -504,11 +456,36 @@ td.group-title {
 .views-ui-display-tab-bucket + .views-ui-display-tab-bucket {
   border-top: medium none;
 }
-.views-ui-display-tab-bucket__title,
+
+.views-ui-display-tab-actions.views-ui-display-tab-bucket {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin-bottom: 15px;
+  padding-bottom: 4px;
+  border: 1px solid #f3f3f3;
+  line-height: 20px;
+}
+.views-ui-views-tab-bucket-actions {
+  margin-right: 5px; /* LTR */
+}
+[dir="rtl"] .views-ui-views-tab-bucket-actions {
+  margin-right: 0;
+  margin-left: 5px;
+}
+
+.views-ui-display-tab-bucket__header {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+}
+
+.views-ui-display-tab-bucket__header,
 .views-ui-display-tab-bucket > .views-display-setting {
   padding: 2px 6px 4px;
 }
 .views-ui-display-tab-bucket__title {
+  flex-grow: 1;
   margin: 0;
   font-size: small;
 }
@@ -551,7 +528,8 @@ td.group-title {
 .views-ui-display-tab-bucket .views-display-setting:nth-of-type(even) {
   background-color: #f3f5ee;
 }
-.views-ui-display-tab-actions.views-ui-display-tab-bucket .views-display-setting {
+.views-ui-display-tab-actions .views-display-setting {
+  flex-grow: 1;
   background-color: transparent;
 }
 .views-ui-display-tab-bucket .views-group-text {
@@ -767,80 +745,6 @@ td.group-title {
   margin-bottom: 18px;
   line-height: 1.4555;
 }
-.dropbutton-multiple {
-  position: absolute;
-}
-.dropbutton-widget {
-  position: relative;
-}
-.js .views-edit-view .dropbutton-wrapper .dropbutton .dropbutton-action > * {
-  font-size: 10px;
-}
-.js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  position: absolute;
-  z-index: 2;
-  top: -1px;
-  right: -5px; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  right: auto;
-  left: -5px;
-}
-.js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:first-child a {
-  border-radius: 1.1em 0 0 0; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:first-child a {
-  border-radius: 0 1.1em 0 0;
-}
-.js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:last-child a {
-  border-radius: 0 0 0 1.1em; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:last-child a {
-  border-radius: 0 0 1.1em 0;
-}
-.views-display-top .dropbutton-wrapper {
-  position: absolute;
-  top: 7px;
-  right: 12px; /* LTR */
-}
-[dir="rtl"] .views-display-top .dropbutton-wrapper {
-  right: auto;
-  left: 12px;
-}
-.views-display-top .dropbutton-wrapper .dropbutton-widget .dropbutton-action a {
-  width: auto;
-}
-
-.views-ui-display-tab-bucket .dropbutton-wrapper {
-  position: absolute;
-  top: 4px;
-  right: 5px; /* LTR */
-}
-[dir="rtl"] .views-ui-display-tab-bucket .dropbutton-wrapper {
-  right: auto;
-  left: 5px;
-}
-.views-ui-display-tab-bucket .dropbutton-wrapper .dropbutton-widget .dropbutton-action a {
-  width: auto;
-}
-.views-ui-display-tab-actions .dropbutton-wrapper li a,
-.views-ui-display-tab-actions .dropbutton-wrapper input {
-  margin-bottom: 0;
-  padding-left: 12px; /* LTR */
-  border: medium;
-  background: none;
-  font-family: inherit;
-  font-size: 12px;
-}
-[dir="rtl"] .views-ui-display-tab-actions .dropbutton-wrapper li a,
-[dir="rtl"] .views-ui-display-tab-actions .dropbutton-wrapper input {
-  padding-right: 12px;
-  padding-left: 0.5em;
-}
-.views-ui-display-tab-actions .dropbutton-wrapper input:hover {
-  border: none;
-  background: none;
-}
 .views-list-section {
   margin-bottom: 2em;
 }
diff --git a/core/modules/views_ui/js/views-admin.es6.js b/core/modules/views_ui/js/views-admin.es6.js
index 289cfea15e..6826ab7594 100644
--- a/core/modules/views_ui/js/views-admin.es6.js
+++ b/core/modules/views_ui/js/views-admin.es6.js
@@ -368,71 +368,12 @@
         return;
       }
 
-      const $addDisplayDropdown = $(
-        `<li class="add"><a href="#"><span class="icon add"></span>${Drupal.t(
-          'Add',
-        )}</a><ul class="action-list" style="display:none;"></ul></li>`,
-      );
-      const $displayButtons = $menu.nextAll('input.add-display').detach();
-      $displayButtons
-        .appendTo($addDisplayDropdown.find('.action-list'))
-        .wrap('<li>')
-        .parent()
-        .eq(0)
-        .addClass('first')
-        .end()
-        .eq(-1)
-        .addClass('last');
-      // Remove the 'Add ' prefix from the button labels since they're being
-      // placed in an 'Add' dropdown. @todo This assumes English, but so does
-      // $addDisplayDropdown above. Add support for translation.
-      $displayButtons.each(function() {
-        const label = $(this).val();
-        if (label.substr(0, 4) === 'Add ') {
-          $(this).val(label.substr(4));
-        }
-      });
-      $addDisplayDropdown.appendTo($menu);
-
-      // Add the click handler for the add display button.
-      $menu.find('li.add > a').on('click', function(event) {
-        event.preventDefault();
-        const $trigger = $(this);
-        Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-      });
-      // Add a mouseleave handler to close the dropdown when the user mouses
-      // away from the item. We use mouseleave instead of mouseout because
-      // the user is going to trigger mouseout when moving away from the trigger
-      // link to the sub menu items.
-      // We use the live binder because the open class on this item will be
-      // toggled on and off and we want the handler to take effect in the cases
-      // that the class is present, but not when it isn't.
-      $('li.add', $menu).on('mouseleave', function(event) {
-        const $this = $(this);
-        const $trigger = $this.children('a[href="#"]');
-        if ($this.children('.action-list').is(':visible')) {
-          Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-        }
-      });
+      $('<li class="add"></li>')
+        .appendTo($menu)
+        .append($menu.next('.js-splitbutton'));
     },
   };
 
-  /**
-   * Toggle menu visibility.
-   *
-   * @param {jQuery} $trigger
-   *   The element where the toggle was triggered.
-   *
-   *
-   * @note [@jessebeach] I feel like the following should be a more generic
-   *   function and not written specifically for this UI, but I'm not sure
-   *   where to put it.
-   */
-  Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function($trigger) {
-    $trigger.parent().toggleClass('open');
-    $trigger.next().slideToggle('fast');
-  };
-
   /**
    * Add search options to the views ui.
    *
diff --git a/core/modules/views_ui/js/views-admin.js b/core/modules/views_ui/js/views-admin.js
index 5cc0ef29d3..b34c18ff58 100644
--- a/core/modules/views_ui/js/views-admin.js
+++ b/core/modules/views_ui/js/views-admin.js
@@ -171,39 +171,10 @@
         return;
       }
 
-      var $addDisplayDropdown = $('<li class="add"><a href="#"><span class="icon add"></span>' + Drupal.t('Add') + '</a><ul class="action-list" style="display:none;"></ul></li>');
-      var $displayButtons = $menu.nextAll('input.add-display').detach();
-      $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('<li>').parent().eq(0).addClass('first').end().eq(-1).addClass('last');
-
-      $displayButtons.each(function () {
-        var label = $(this).val();
-        if (label.substr(0, 4) === 'Add ') {
-          $(this).val(label.substr(4));
-        }
-      });
-      $addDisplayDropdown.appendTo($menu);
-
-      $menu.find('li.add > a').on('click', function (event) {
-        event.preventDefault();
-        var $trigger = $(this);
-        Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-      });
-
-      $('li.add', $menu).on('mouseleave', function (event) {
-        var $this = $(this);
-        var $trigger = $this.children('a[href="#"]');
-        if ($this.children('.action-list').is(':visible')) {
-          Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
-        }
-      });
+      $('<li class="add"></li>').appendTo($menu).append($menu.next('.js-splitbutton'));
     }
   };
 
-  Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function ($trigger) {
-    $trigger.parent().toggleClass('open');
-    $trigger.next().slideToggle('fast');
-  };
-
   Drupal.behaviors.viewsUiSearchOptions = {
     attach: function attach(context) {
       var $context = $(context);
diff --git a/core/modules/views_ui/src/ViewEditForm.php b/core/modules/views_ui/src/ViewEditForm.php
index 8ca5612dbb..f2302818c8 100644
--- a/core/modules/views_ui/src/ViewEditForm.php
+++ b/core/modules/views_ui/src/ViewEditForm.php
@@ -402,22 +402,20 @@ public function getDisplayDetails($view, $display) {
 
       // The Delete, Duplicate and Undo Delete buttons.
       $build['top']['actions'] = [
-        '#theme_wrappers' => ['dropbutton_wrapper'],
+        '#type' => 'splitbutton',
+        '#splitbutton_type' => ['extrasmall'],
+        '#attributes' => [
+          'class' => ['views-ui-views-tab-bucket-actions'],
+        ],
+        '#weight' => 100,
       ];
-
-      // Because some of the 'links' are actually submit buttons, we have to
-      // manually wrap each item in <li> and the whole list in <ul>.
-      $build['top']['actions']['prefix']['#markup'] = '<ul class="dropbutton">';
-
       if (!$is_display_deleted) {
         if (!$is_enabled) {
-          $build['top']['actions']['enable'] = [
+          $build['top']['actions']['#items']['enable'] = [
             '#type' => 'submit',
             '#value' => $this->t('Enable @display_title', ['@display_title' => $display_title]),
             '#limit_validation_errors' => [],
             '#submit' => ['::submitDisplayEnable', '::submitDelayDestination'],
-            '#prefix' => '<li class="enable">',
-            "#suffix" => '</li>',
           ];
         }
         // Add a link to view the page unless the view is disabled or has no
@@ -443,34 +441,28 @@ public function getDisplayDetails($view, $display) {
               $url = '/' . $path;
             }
 
-            $build['top']['actions']['path'] = [
+            $build['top']['actions']['#items']['path'] = [
               '#type' => 'link',
               '#title' => $this->t('View @display_title', ['@display_title' => $display_title]),
               '#options' => ['alt' => [$this->t("Go to the real page for this display")]],
               '#url' => $url,
-              '#prefix' => '<li class="view">',
-              "#suffix" => '</li>',
             ];
           }
         }
         if (!$is_default) {
-          $build['top']['actions']['duplicate'] = [
+          $build['top']['actions']['#items']['duplicate'] = [
             '#type' => 'submit',
             '#value' => $this->t('Duplicate @display_title', ['@display_title' => $display_title]),
             '#limit_validation_errors' => [],
             '#submit' => ['::submitDisplayDuplicate', '::submitDelayDestination'],
-            '#prefix' => '<li class="duplicate">',
-            "#suffix" => '</li>',
           ];
         }
         // Always allow a display to be deleted.
-        $build['top']['actions']['delete'] = [
+        $build['top']['actions']['#items']['delete'] = [
           '#type' => 'submit',
           '#value' => $this->t('Delete @display_title', ['@display_title' => $display_title]),
           '#limit_validation_errors' => [],
           '#submit' => ['::submitDisplayDelete', '::submitDelayDestination'],
-          '#prefix' => '<li class="delete">',
-          "#suffix" => '</li>',
         ];
 
         foreach (Views::fetchPluginNames('display', NULL, [$view->get('storage')->get('base_table')]) as $type => $label) {
@@ -478,37 +470,30 @@ public function getDisplayDetails($view, $display) {
             continue;
           }
 
-          $build['top']['actions']['duplicate_as'][$type] = [
+          $build['top']['actions']['#items']['duplicate_as_' . $type] = [
             '#type' => 'submit',
             '#value' => $this->t('Duplicate as @type', ['@type' => $label]),
             '#limit_validation_errors' => [],
             '#submit' => ['::submitDuplicateDisplayAsType', '::submitDelayDestination'],
-            '#prefix' => '<li class="duplicate">',
-            '#suffix' => '</li>',
           ];
         }
       }
       else {
-        $build['top']['actions']['undo_delete'] = [
+        $build['top']['actions']['#items']['undo_delete'] = [
           '#type' => 'submit',
           '#value' => $this->t('Undo delete of @display_title', ['@display_title' => $display_title]),
           '#limit_validation_errors' => [],
           '#submit' => ['::submitDisplayUndoDelete', '::submitDelayDestination'],
-          '#prefix' => '<li class="undo-delete">',
-          "#suffix" => '</li>',
         ];
       }
       if ($is_enabled) {
-        $build['top']['actions']['disable'] = [
+        $build['top']['actions']['#items']['disable'] = [
           '#type' => 'submit',
           '#value' => $this->t('Disable @display_title', ['@display_title' => $display_title]),
           '#limit_validation_errors' => [],
           '#submit' => ['::submitDisplayDisable', '::submitDelayDestination'],
-          '#prefix' => '<li class="disable">',
-          "#suffix" => '</li>',
         ];
       }
-      $build['top']['actions']['suffix']['#markup'] = '</ul>';
 
       // The area above the three columns.
       $build['top']['display_title'] = [
@@ -704,61 +689,77 @@ public function renderDisplayTop(ViewUI $view) {
     $element['#attributes']['class'] = ['views-display-top', 'clearfix'];
     $element['#attributes']['id'] = ['views-display-top'];
 
-    // Extra actions for the display
-    $element['extra_actions'] = [
-      '#type' => 'dropbutton',
-      '#attributes' => [
-        'id' => 'views-display-extra-actions',
-      ],
-      '#links' => [
-        'edit-details' => [
-          'title' => $this->t('Edit view name/description'),
-          'url' => Url::fromRoute('views_ui.form_edit_details', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id]),
+    // Extra actions for the display.
+    $extra_actions_links = [
+      'edit-details' => [
+        '#type' => 'link',
+        '#title' => $this->t('Edit view name/description'),
+        '#url' => Url::fromRoute('views_ui.form_edit_details', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id], [
           'attributes' => ['class' => ['views-ajax-link']],
-        ],
-        'analyze' => [
-          'title' => $this->t('Analyze view'),
-          'url' => Url::fromRoute('views_ui.form_analyze', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id]),
+        ]),
+      ],
+      'analyze' => [
+        '#type' => 'link',
+        '#title' => $this->t('Analyze view'),
+        '#url' => Url::fromRoute('views_ui.form_analyze', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id], [
           'attributes' => ['class' => ['views-ajax-link']],
-        ],
-        'duplicate' => [
-          'title' => $this->t('Duplicate view'),
-          'url' => $view->toUrl('duplicate-form'),
-        ],
-        'reorder' => [
-          'title' => $this->t('Reorder displays'),
-          'url' => Url::fromRoute('views_ui.form_reorder_displays', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id]),
+        ]),
+      ],
+      'duplicate' => [
+        '#type' => 'link',
+        '#title' => $this->t('Duplicate view'),
+        '#url' => $view->toUrl('duplicate-form'),
+      ],
+      'reorder' => [
+        '#type' => 'link',
+        '#title' => $this->t('Reorder displays'),
+        '#url' => Url::fromRoute('views_ui.form_reorder_displays', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display_id], [
           'attributes' => ['class' => ['views-ajax-link']],
-        ],
+        ]),
       ],
     ];
 
     if ($view->access('delete')) {
-      $element['extra_actions']['#links']['delete'] = [
-        'title' => $this->t('Delete view'),
-        'url' => $view->toUrl('delete-form'),
+      $extra_actions_links['delete'] = [
+        '#type' => 'link',
+        '#title' => $this->t('Delete view'),
+        '#url' => $view->toUrl('delete-form'),
       ];
     }
 
     // Let other modules add additional links here.
-    \Drupal::moduleHandler()->alter('views_ui_display_top_links', $element['extra_actions']['#links'], $view, $display_id);
+    \Drupal::moduleHandler()->alter('views_ui_display_top_links', $extra_actions_links, $view, $display_id);
 
     if (isset($view->type) && $view->type != $this->t('Default')) {
       if ($view->type == $this->t('Overridden')) {
-        $element['extra_actions']['#links']['revert'] = [
-          'title' => $this->t('Revert view'),
-          'href' => "admin/structure/views/view/{$view->id()}/revert",
-          'query' => ['destination' => $view->toUrl('edit-form')->toString()],
+        $extra_actions_links['revert'] = [
+          '#type' => 'link',
+          '#title' => $this->t('Revert view'),
+          '#url' => Url::fromUri("internal:/admin/structure/views/view/{$view->id()}/revert", [
+            'query' => ['destination' => $view->toUrl('edit-form')->toString()],
+          ]),
         ];
       }
       else {
-        $element['extra_actions']['#links']['delete'] = [
-          'title' => $this->t('Delete view'),
-          'url' => $view->toUrl('delete-form'),
+        $extra_actions_links['delete'] = [
+          '#type' => 'link',
+          '#title' => $this->t('Delete view'),
+          '#url' => $view->toUrl('delete-form'),
         ];
       }
     }
 
+    $element['extra_actions'] = [
+      '#type' => 'splitbutton',
+      '#splitbutton_type' => ['small'],
+      '#attributes' => [
+        'id' => 'views-display-extra-actions',
+        'class' => ['views-ui-views-extra-actions'],
+      ],
+      '#items' => $extra_actions_links,
+      '#weight' => 100,
+    ];
+
     // Determine the displays available for editing.
     if ($tabs = $this->getDisplayTabs($view)) {
       if ($display_id) {
@@ -770,8 +771,18 @@ public function renderDisplayTop(ViewUI $view) {
     }
 
     // Buttons for adding a new display.
+    $element['add_display'] = [
+      '#type' => 'splitbutton',
+      '#splitbutton_type' => ['extrasmall'],
+      '#main_items' => FALSE,
+      '#trigger_label' => $this->t('Add'),
+      '#trigger_label_visible' => TRUE,
+      '#attributes' => [
+        'class' => ['views-ui-views-display-add-actions'],
+      ],
+    ];
     foreach (Views::fetchPluginNames('display', NULL, [$view->get('base_table')]) as $type => $label) {
-      $element['add_display'][$type] = [
+      $element['add_display']['#items'][$type] = [
         '#type' => 'submit',
         '#value' => $this->t('Add @display', ['@display' => $label]),
         '#limit_validation_errors' => [],
@@ -894,7 +905,8 @@ public function submitDuplicateDisplayAsType($form, FormStateInterface $form_sta
 
     // Create the new display.
     $parents = $form_state->getTriggeringElement()['#parents'];
-    $display_type = array_pop($parents);
+
+    $display_type = str_replace('duplicate_as_', '', array_pop($parents));
 
     $new_display_id = $view->duplicateDisplayAsType($display_id, $display_type);
 
@@ -968,7 +980,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
     $build['#title'] = $types[$type]['title'];
 
     $rearrange_url = Url::fromRoute('views_ui.form_rearrange', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display['id'], 'type' => $type]);
-    $class = 'icon compact rearrange';
+    $class = 'rearrange';
 
     // Different types now have different rearrange forms, so we use this switch
     // to get the right one.
@@ -978,7 +990,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
         // the used path.
         $rearrange_url = Url::fromRoute('views_ui.form_rearrange_filter', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display['id']]);
         // TODO: Add another class to have another symbol for filter rearrange.
-        $class = 'icon compact rearrange';
+        $class = 'rearrange';
         break;
       case 'field':
         // Fetch the style plugin info so we know whether to list fields or not.
@@ -1017,7 +1029,7 @@ public function getFormBucket(ViewUI $view, $type, $display) {
     $actions['add'] = [
       'title' => $add_text,
       'url' => Url::fromRoute('views_ui.form_add_handler', ['js' => 'nojs', 'view' => $view->id(), 'display_id' => $display['id'], 'type' => $type]),
-      'attributes' => ['class' => ['icon compact add', 'views-ajax-link'], 'id' => 'views-add-' . $type],
+      'attributes' => ['class' => ['add', 'views-ajax-link'], 'id' => 'views-add-' . $type],
     ];
     if ($count_handlers > 0) {
       // Create the rearrange text variable for the rearrange action.
@@ -1032,8 +1044,9 @@ public function getFormBucket(ViewUI $view, $type, $display) {
 
     // Render the array of links
     $build['#actions'] = [
-      '#type' => 'dropbutton',
-      '#links' => $actions,
+      '#type' => 'splitbutton',
+      '#splitbutton_type' => ['extrasmall'],
+      '#items' => $actions,
       '#attributes' => [
         'class' => ['views-ui-settings-bucket-operations'],
       ],
diff --git a/core/modules/views_ui/templates/views-ui-display-tab-bucket.html.twig b/core/modules/views_ui/templates/views-ui-display-tab-bucket.html.twig
index 88ab1bd6a1..c0d6444c6b 100644
--- a/core/modules/views_ui/templates/views-ui-display-tab-bucket.html.twig
+++ b/core/modules/views_ui/templates/views-ui-display-tab-bucket.html.twig
@@ -25,11 +25,13 @@
   ]
 %}
 <div{{ attributes.addClass(classes) }}>
-  {% if title -%}
+  <div class="views-ui-display-tab-bucket__header">
+    {% if title -%}
     <h3 class="views-ui-display-tab-bucket__title">{{ title }}</h3>
-  {%- endif %}
-  {% if actions -%}
+    {%- endif %}
+    {% if actions -%}
     {{ actions }}
-  {%- endif %}
+    {%- endif %}
+  </div>
   {{ content }}
 </div>
diff --git a/core/modules/views_ui/tests/src/Functional/DisplayTest.php b/core/modules/views_ui/tests/src/Functional/DisplayTest.php
index d2b03327eb..0de6f42cc3 100644
--- a/core/modules/views_ui/tests/src/Functional/DisplayTest.php
+++ b/core/modules/views_ui/tests/src/Functional/DisplayTest.php
@@ -246,7 +246,7 @@ public function testActionLinks() {
     $this->assertEscaped($display_title);
     $this->assertNoRaw($display_title);
 
-    // Ensure that the dropdown buttons are displayed correctly.
+    // Ensure that the splitbuttons are displayed correctly.
     $this->assertFieldByXpath('//input[@type="submit"]', 'Duplicate ' . $display_title);
     $this->assertFieldByXpath('//input[@type="submit"]', 'Delete ' . $display_title);
     $this->assertFieldByXpath('//input[@type="submit"]', 'Disable ' . $display_title);
diff --git a/core/modules/views_ui/tests/src/FunctionalJavascript/FilterCriteriaTest.php b/core/modules/views_ui/tests/src/FunctionalJavascript/FilterCriteriaTest.php
index 1f28058fa9..9aa35adbc7 100644
--- a/core/modules/views_ui/tests/src/FunctionalJavascript/FilterCriteriaTest.php
+++ b/core/modules/views_ui/tests/src/FunctionalJavascript/FilterCriteriaTest.php
@@ -131,8 +131,8 @@ public function testFilterCriteriaDialog() {
   protected function openFilterDialog() {
     $assert_session = $this->assertSession();
     $page = $this->getSession()->getPage();
-    $dropbutton = $page->find('css', '.views-ui-display-tab-bucket.filter .dropbutton-toggle button');
-    $dropbutton->click();
+    $splitbutton = $page->find('css', '.views-ui-display-tab-bucket.filter .js-splitbutton-toggle');
+    $splitbutton->click();
     $add_link = $page->findById('views-rearrange-filter');
     $this->assertTrue($add_link->isVisible(), 'And/Or Rearrange button found.');
     $add_link->click();
diff --git a/core/modules/views_ui/tests/src/FunctionalJavascript/ViewsListingTest.php b/core/modules/views_ui/tests/src/FunctionalJavascript/ViewsListingTest.php
index f6a9976dcf..cbf23500e6 100644
--- a/core/modules/views_ui/tests/src/FunctionalJavascript/ViewsListingTest.php
+++ b/core/modules/views_ui/tests/src/FunctionalJavascript/ViewsListingTest.php
@@ -99,8 +99,8 @@ public function testFilterViewsListing() {
     $enabled_view = $page->find('css', 'tr.views-ui-list-enabled');
     $view_description = $enabled_view->find('css', '.views-ui-view-name h3')->getText();
     // Open the dropdown with additional actions.
-    $enabled_view->find('css', 'li.dropbutton-toggle button')->click();
-    $disable_button = $enabled_view->find('css', 'li.disable.dropbutton-action a');
+    $enabled_view->find('css', '.js-splitbutton-toggle')->click();
+    $disable_button = $enabled_view->findLink('Disable');
     // Check that the disable button is visible now.
     $this->assertTrue($disable_button->isVisible());
     $disable_button->click();
@@ -118,14 +118,14 @@ public function testFilterViewsListing() {
 
     // Test that the keyboard focus is on the dropdown button of the View we
     // just disabled.
-    $this->assertTrue($this->getSession()->evaluateScript("jQuery(document.activeElement).parent().is('li.enable.dropbutton-action')"));
+    $this->assertTrue($this->getSession()->evaluateScript("jQuery(document.activeElement).text() === 'Enable'"));
     $this->assertEquals($view_description, $this->getSession()->evaluateScript("jQuery(document.activeElement).parents('tr').find('h3').text()"));
 
     // Enable the view again and ensure we have the focus on the edit button.
     $this->getSession()->evaluateScript('jQuery(document.activeElement).click()');
     $session->assertWaitOnAjaxRequest();
 
-    $this->assertTrue($this->getSession()->evaluateScript("jQuery(document.activeElement).parent().is('li.edit.dropbutton-action')"));
+    $this->assertTrue($this->getSession()->evaluateScript("jQuery(document.activeElement).text() === 'Edit'"));
     $this->assertEquals($view_description, $this->getSession()->evaluateScript("jQuery(document.activeElement).parents('tr').find('h3').text()"));
   }
 
diff --git a/core/modules/workflows/src/Form/WorkflowEditForm.php b/core/modules/workflows/src/Form/WorkflowEditForm.php
index 0f783f4c04..b2fad07a0d 100644
--- a/core/modules/workflows/src/Form/WorkflowEditForm.php
+++ b/core/modules/workflows/src/Form/WorkflowEditForm.php
@@ -140,8 +140,8 @@ public function form(array $form, FormStateInterface $form_state) {
           '#delta' => $state_weight_delta,
         ],
         'operations' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
     }
@@ -205,8 +205,8 @@ public function form(array $form, FormStateInterface $form_state) {
         ],
         'to' => ['#markup' => $transition->to()->label()],
         'operations' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
     }
diff --git a/core/modules/workflows/src/Form/WorkflowStateEditForm.php b/core/modules/workflows/src/Form/WorkflowStateEditForm.php
index 0ecc3cde6b..cb85562cf4 100644
--- a/core/modules/workflows/src/Form/WorkflowStateEditForm.php
+++ b/core/modules/workflows/src/Form/WorkflowStateEditForm.php
@@ -139,8 +139,8 @@ public function form(array $form, FormStateInterface $form_state) {
           '#markup' => $transition->to()->label(),
         ],
         'operations' => [
-          '#type' => 'operations',
-          '#links' => $links,
+          '#type' => 'splitbutton_operations',
+          '#items' => $links,
         ],
       ];
     }
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Theme/ClaroViewsUiTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Theme/ClaroViewsUiTest.php
index 66afcb4619..38735a8c00 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Theme/ClaroViewsUiTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Theme/ClaroViewsUiTest.php
@@ -70,11 +70,15 @@ public function testViewsUiTabsCssClasses() {
   public function testViewsUiDropButtonCssClasses() {
     $this->drupalGet('admin/structure/views/view/who_s_online');
     $assert_session = $this->assertSession();
-    $extra_actions_dropbutton_list = $assert_session->elementExists('css', '#views-display-extra-actions.dropbutton--small');
-    $list_item_selectors = ['li:first-child', 'li:last-child'];
+    $extra_actions_splitbutton = $assert_session->elementExists('css', '#views-display-extra-actions.splitbutton--small');
+    $splitbutton_item_selectors = [
+      'div.splitbutton__main-items .splitbutton__action--main',
+      'li:first-child .views-ajax-link.splitbutton__action--secondary',
+      'li:last-child .splitbutton__action--secondary',
+    ];
     // Test list item CSS classes.
-    foreach ($list_item_selectors as $list_item_selector) {
-      $this->assertNotNull($extra_actions_dropbutton_list->find('css', "$list_item_selector.dropbutton__item.dropbutton__item--small"));
+    foreach ($splitbutton_item_selectors as $splitbutton_item_selector) {
+      $this->assertNotNull($extra_actions_splitbutton->find('css', $splitbutton_item_selector));
     }
 
     // Click on the Display name and wait for the Views UI dialog.
@@ -86,10 +90,10 @@ public function testViewsUiDropButtonCssClasses() {
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Check that the drop button list still has the expected CSS classes.
-    $this->assertTrue($extra_actions_dropbutton_list->hasClass('dropbutton--small'));
+    $this->assertTrue($extra_actions_splitbutton->hasClass('splitbutton--small'));
     // Check list item CSS classes.
-    foreach ($list_item_selectors as $list_item_selector) {
-      $this->assertNotNull($extra_actions_dropbutton_list->find('css', "$list_item_selector.dropbutton__item.dropbutton__item--small"));
+    foreach ($splitbutton_item_selectors as $splitbutton_item_selector) {
+      $this->assertNotNull($extra_actions_splitbutton->find('css', $splitbutton_item_selector));
     }
   }
 
diff --git a/core/themes/bartik/bartik.info.yml b/core/themes/bartik/bartik.info.yml
index 130d583c91..61eacecd29 100644
--- a/core/themes/bartik/bartik.info.yml
+++ b/core/themes/bartik/bartik.info.yml
@@ -20,6 +20,11 @@ version: VERSION
 core: 8.x
 libraries:
   - bartik/global-styling
+
+libraries-extend:
+  core/drupal.splitbutton:
+    - bartik/drupal.splitbutton
+
 ckeditor_stylesheets:
   - css/base/elements.css
   - css/components/captions.css
diff --git a/core/themes/bartik/bartik.libraries.yml b/core/themes/bartik/bartik.libraries.yml
index 3bbecd932f..aa29e55c21 100644
--- a/core/themes/bartik/bartik.libraries.yml
+++ b/core/themes/bartik/bartik.libraries.yml
@@ -85,3 +85,9 @@ maintenance_page:
   dependencies:
     - system/maintenance
     - bartik/global-styling
+
+drupal.splitbutton:
+  version: VERSION
+  css:
+    component:
+      css/components/splitbutton.css: {}
diff --git a/core/themes/bartik/css/components/buttons.css b/core/themes/bartik/css/components/buttons.css
index 501c9dee36..b8620ad350 100644
--- a/core/themes/bartik/css/components/buttons.css
+++ b/core/themes/bartik/css/components/buttons.css
@@ -3,6 +3,11 @@
  * Styles for Bartik's buttons.
  */
 
+/**
+ * These styles have been duplicated to splitbutton.css since that component
+ * inherits most of these design elements. Whenever making changes to this file,
+ * remember to check if that needs to be applied to splitbutton.css as well.
+ */
 .button {
   display: inline-block;
   padding: 0.25em 1.063em;
diff --git a/core/themes/bartik/css/components/splitbutton.css b/core/themes/bartik/css/components/splitbutton.css
new file mode 100644
index 0000000000..9a78b17c70
--- /dev/null
+++ b/core/themes/bartik/css/components/splitbutton.css
@@ -0,0 +1,164 @@
+/**
+ * @file
+ * Splitbuttons.
+ */
+
+.splitbutton {
+  font-size: 0.929em;
+  line-height: normal;
+}
+
+.splitbutton--small,
+.splitbutton--extrasmall {
+  font-size: 10px;
+  line-height: 1.5;
+}
+
+.splitbutton__action--main.splitbutton__action--main,
+.splitbutton__toggle.splitbutton__toggle {
+  margin: 0;
+  border: 1px solid #e4e4e4;
+  border-right-color: #d2d2d2;
+  border-bottom-color: #b4b4b4;
+  border-left-color: #d2d2d2;
+  border-radius: 0;
+}
+
+.splitbutton__action--main.splitbutton__action--main:first-child,
+.splitbutton__toggle.splitbutton__toggle:first-child {
+  border-top-left-radius: 1em; /* LTR */
+  border-bottom-left-radius: 1em; /* LTR */
+}
+
+.splitbutton__action--main.splitbutton__action--main:last-child,
+.splitbutton__toggle.splitbutton__toggle:last-child {
+  border-top-right-radius: 1em; /* LTR */
+  border-bottom-right-radius: 1em; /* LTR */
+}
+
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle {
+  border-radius: 0;
+}
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle:first-child {
+  border-top-right-radius: 1em;
+  border-bottom-right-radius: 1em;
+}
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle:last-child {
+  border-top-left-radius: 1em;
+  border-bottom-left-radius: 1em;
+}
+
+.splitbutton__toggle--no-label,
+.splitbutton__toggle--no-label:hover,
+.splitbutton__toggle--no-label:focus {
+  min-width: 1.75rem;
+  padding: 0.1rem 0.5rem;
+  color: #000;
+  background: #e8e8e8;
+  background-image: -webkit-linear-gradient(top, #e8e8e8, #d2d2d2);
+  background-image: linear-gradient(to bottom, #e8e8e8, #d2d2d2);
+}
+
+.splitbutton__toggle-arrow {
+  font-size: 0.8125rem;
+}
+
+/* Splitbutton list */
+.splitbutton__list,
+[dir="rtl"] .splitbutton__list {
+  padding: 0.25em 0;
+}
+
+/**
+ * Styles for the main splitbutton items.
+ * Duplicates base button styles.
+ */
+.splitbutton__action--main.splitbutton__action--main {
+  display: inline-block;
+  padding: 0.25em 1em; /* Mixed from dropbutton.component.css and buttons.css */
+  cursor: pointer;
+  text-align: center;
+  color: #3a3a3a;
+  border: 1px solid #e4e4e4;
+  border-right-color: #d2d2d2;
+  border-bottom-color: #b4b4b4;
+  border-left-color: #d2d2d2;
+  background-color: #fff;
+  background-image: -webkit-linear-gradient(top, #f3f3f3, #e8e8e8);
+  background-image: linear-gradient(to bottom, #f3f3f3, #e8e8e8);
+  font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, sans-serif;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+.splitbutton__action--main.splitbutton__action--main:hover,
+.splitbutton__action--main.splitbutton__action--main:active,
+.splitbutton__action--main.splitbutton__action--main:focus {
+  text-decoration: none;
+  color: #5a5a5a;
+  background: #dedede;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary {
+  margin: 0;
+  padding: 0.33em 1em;
+  text-align: left; /* LTR */
+  border: 0;
+  border-radius: 0;
+  font: inherit;
+  -webkit-font-smoothing: inherit;
+}
+[dir="rtl"] .splitbutton__action--secondary.splitbutton__action--secondary {
+  text-align: right;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary,
+.splitbutton__action--secondary.splitbutton__action--secondary:active,
+.splitbutton__action--secondary.splitbutton__action--secondary:focus {
+  color: #000;
+  background: #fff;
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: 0.5em 1em;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:hover {
+  text-decoration: none;
+  color: #000;
+  background: #c7eaff;
+  box-shadow: none;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:focus {
+  text-decoration: underline;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:focus:hover {
+  text-decoration: none;
+}
+
+/**
+ * Style overrides for views_ui add display splitbutton.
+ */
+.views-ui-views-display-add-actions.splitbutton {
+  font-size: 0.929em;
+  line-height: normal;
+}
+.views-ui-views-display-add-actions.splitbutton.splitbutton .splitbutton__toggle {
+  border-radius: 7px;
+}
+
+.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:not(:hover) {
+  color: #0071b3;
+  background: #fff;
+}
+
+.views-ui-views-display-add-actions.splitbutton .splitbutton__list {
+  font-size: inherit;
+  line-height: inherit;
+}
diff --git a/core/themes/bartik/css/components/views.css b/core/themes/bartik/css/components/views.css
index 1e45f57953..36aaf7bf5a 100644
--- a/core/themes/bartik/css/components/views.css
+++ b/core/themes/bartik/css/components/views.css
@@ -4,22 +4,10 @@
  */
 
 /* Tab styles */
-.views-displays .tabs .open > a {
-  border-radius: 7px 7px 0 0;
-}
-.views-displays .tabs .open > a:hover,
-.views-displays .tabs .open > a:focus {
-  color: #0071b3;
-}
 .views-displays .secondary .form-submit {
   font-size: 0.846em;
 }
 
-/* Tabs action list styles */
-.views-displays .tabs .action-list {
-  padding: 0;
-}
-
 /* Contextual filter options styles */
 .views-filterable-options .filterable-option:nth-of-type(even) .form-type-checkbox {
   background-color: #f9f9f9;
diff --git a/core/themes/claro/claro.info.yml b/core/themes/claro/claro.info.yml
index 71412c9573..b7a5d7ea35 100644
--- a/core/themes/claro/claro.info.yml
+++ b/core/themes/claro/claro.info.yml
@@ -120,6 +120,11 @@ libraries-override:
       theme:
         /core/themes/stable/css/views_ui/views_ui.admin.theme.css: css/theme/views_ui.admin.theme.css
 
+  core/drupal.splitbutton:
+    css:
+      component:
+        /core/themes/stable/css/core/splitbutton/splitbutton.css: css/components/splitbutton.css
+
 libraries-extend:
   ckeditor/drupal.ckeditor:
     - claro/ckeditor-editor
diff --git a/core/themes/claro/claro.theme b/core/themes/claro/claro.theme
index d778310518..0121f06301 100644
--- a/core/themes/claro/claro.theme
+++ b/core/themes/claro/claro.theme
@@ -540,61 +540,11 @@ function claro_views_ui_display_top_alter(&$element) {
 
   // Change top extra actions to use the small dropbutton variant.
   // @todo Revisit after https://www.drupal.org/node/3057581 is added.
-  if (!empty($element['extra_actions'])) {
+  if (!empty($element['extra_actions']) && !empty($element['extra_actions']['#type']) && $element['extra_actions']['#type'] === 'dropbutton') {
     $element['extra_actions']['#dropbutton_type'] = 'small';
   }
 }
 
-/**
- * Implements hook_views_ui_display_tab_alter().
- */
-function claro_views_ui_display_tab_alter(&$element) {
-  // We process the dropbutton-like element on views edit form's
-  // display settings top section.
-  //
-  // That element should be a regular Dropbutton.
-  //
-  // After that the reported issue is fixed and the element is rendered with
-  // the Dropbutton type, we just have to set it's '#dropbutton_type' to
-  // 'extrasmall'.
-  //
-  // @todo: revisit after https://www.drupal.org/node/3057577 is fixed.
-  $dummy_dropbutton = &$element['details']['top']['actions'];
-
-  if ($dummy_dropbutton) {
-    $child_keys = Element::children($dummy_dropbutton);
-    $prefix_regex = '/(<.*class\s*= *["\']?)([^"\']*)(.*)/i';
-    $child_count = 0;
-
-    foreach ($child_keys as $key) {
-      if (in_array($key, ['prefix', 'suffix'])) {
-        continue;
-      }
-      $nested_child_keys = Element::children($dummy_dropbutton[$key], TRUE);
-
-      if (!empty($nested_child_keys)) {
-        foreach ($nested_child_keys as $nested_key) {
-          $child_count++;
-          $prefix = $dummy_dropbutton[$key][$nested_key]['#prefix'];
-          $dummy_dropbutton[$key][$nested_key]['#prefix'] = preg_replace($prefix_regex, '$1$2 dropbutton__item dropbutton__item--extrasmall$3', $prefix);
-        }
-      }
-      else {
-        $child_count++;
-        $prefix = $dummy_dropbutton[$key]['#prefix'];
-        $dummy_dropbutton[$key]['#prefix'] = preg_replace($prefix_regex, '$1$2 dropbutton__item dropbutton__item--extrasmall$3', $prefix);
-      }
-    }
-
-    if (!empty($dummy_dropbutton['prefix']) && !empty($dummy_dropbutton['prefix']['#markup'])) {
-      $classes = 'dropbutton--extrasmall ';
-      $classes .= ($child_count > 1) ? 'dropbutton--multiple' : 'dropbutton--single';
-      $prefix = $dummy_dropbutton['prefix']['#markup'];
-      $dummy_dropbutton['prefix']['#markup'] = preg_replace($prefix_regex, '$1$2 ' . $classes . '$3', $prefix);
-    }
-  }
-}
-
 /**
  * Implements hook_form_FORM_ID_alter() for views_exposed_form.
  */
@@ -828,7 +778,7 @@ function claro_preprocess_field_multiple_value_form(&$variables) {
     }
 
     // Make add-more button smaller.
-    if (!empty($variables['button'])) {
+    if (isset($variables['button']['#type']) && $variables['button']['#type'] == 'submit') {
       $variables['button']['#attributes']['class'][] = 'button--small';
     }
   }
@@ -1207,3 +1157,23 @@ function claro_preprocess_image_widget(&$variables) {
   $variables['has_value'] = $has_value;
   $variables['has_meta'] = $alt_is_visible || $title_is_visible;
 }
+
+/**
+ * Implements hook_preprocess_HOOK() for splitbutton__operations.
+ *
+ * Makes operation splitbuttons use the extra small splitbutton variant.
+ *
+ * @TODO replace with prerender.
+ */
+function claro_preprocess_splitbutton__operations(&$variables) {
+  $variables['attributes']['class'] += [];
+  $variables['element']['#splitbutton_type'] = ['extrasmall'];
+
+  if (($small_class_key = array_search('splitbutton--small', $variables['attributes']['class'])) !== FALSE) {
+    unset($variables['attributes']['class'][$small_class_key]);
+  }
+
+  if (array_search('splitbutton--extrasmall', $variables['attributes']['class']) === FALSE) {
+    $variables['attributes']['class'][] = 'splitbutton--extrasmall';
+  }
+}
diff --git a/core/themes/claro/css/components/button.css b/core/themes/claro/css/components/button.css
index e256d271ff..1526759e1e 100644
--- a/core/themes/claro/css/components/button.css
+++ b/core/themes/claro/css/components/button.css
@@ -73,10 +73,11 @@
 /**
  * Base button styles.
  *
- * These styles have been duplicated to dropbutton.css and action-links.css
- * since those components inherits most of these design elements. Whenever
- * making changes to this file, remember to check if that needs to be applied to
- * dropbutton.css or action-links.css as well.
+ * These styles have been duplicated to dropbutton.css, splitbutton.css and
+ * action-links.css since those components inherits most of these design
+ * elements. Whenever making changes to this file, remember to check if that
+ * needs to be applied to dropbutton.css, splitbutton.css or action-links.css as
+ * well.
  */
 
 .button {
diff --git a/core/themes/claro/css/components/button.pcss.css b/core/themes/claro/css/components/button.pcss.css
index 307b5233d6..545c1a060c 100644
--- a/core/themes/claro/css/components/button.pcss.css
+++ b/core/themes/claro/css/components/button.pcss.css
@@ -24,10 +24,11 @@
 /**
  * Base button styles.
  *
- * These styles have been duplicated to dropbutton.css and action-links.css
- * since those components inherits most of these design elements. Whenever
- * making changes to this file, remember to check if that needs to be applied to
- * dropbutton.css or action-links.css as well.
+ * These styles have been duplicated to dropbutton.css, splitbutton.css and
+ * action-links.css since those components inherits most of these design
+ * elements. Whenever making changes to this file, remember to check if that
+ * needs to be applied to dropbutton.css, splitbutton.css or action-links.css as
+ * well.
  */
 .button {
   display: inline-block;
diff --git a/core/themes/claro/css/components/form.css b/core/themes/claro/css/components/form.css
index c2ab325e92..c966ca8e46 100644
--- a/core/themes/claro/css/components/form.css
+++ b/core/themes/claro/css/components/form.css
@@ -201,8 +201,8 @@ tr .form-item,
   margin-bottom: 1rem;
 }
 
-.form-actions .button,
-.form-actions .action-link {
+.form-actions > .button,
+.form-actions > .action-link {
   margin-top: 1rem;
   margin-bottom: 1rem;
 }
diff --git a/core/themes/claro/css/components/form.pcss.css b/core/themes/claro/css/components/form.pcss.css
index a39ea94255..798f32ada8 100644
--- a/core/themes/claro/css/components/form.pcss.css
+++ b/core/themes/claro/css/components/form.pcss.css
@@ -124,8 +124,8 @@ tr .form-item,
   margin-top: var(--space-m);
   margin-bottom: var(--space-m);
 }
-.form-actions .button,
-.form-actions .action-link {
+.form-actions > .button,
+.form-actions > .action-link {
   margin-top: var(--space-m);
   margin-bottom: var(--space-m);
 }
diff --git a/core/themes/claro/css/components/splitbutton.css b/core/themes/claro/css/components/splitbutton.css
new file mode 100644
index 0000000000..475a00b98a
--- /dev/null
+++ b/core/themes/claro/css/components/splitbutton.css
@@ -0,0 +1,330 @@
+/*
+ * DO NOT EDIT THIS FILE.
+ * See the following change record for more information,
+ * https://www.drupal.org/node/2815083
+ * @preserve
+ */
+
+/**
+ * @file
+ * Splitbutton styles.
+ */
+
+:root {
+  /*
+   * Color Palette.
+   */
+  /* Secondary. */
+  /* Variations. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 10% darker than base. */ /* 20% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */
+  /*
+   * Base.
+   */
+  /*
+   * Typography.
+   */ /* 1rem = 16px if font root is 100% ands browser defaults are used. */ /* ~32px */ /* ~29px */ /* ~26px */ /* ~23px */ /* ~20px */ /* 18px */ /* ~14px */ /* ~13px */ /* ~11px */
+  /**
+   * Spaces.
+   */ /* 3 * 16px = 48px */ /* 1.5 * 16px = 24px */ /* 1 * 16px = 16px */ /* 0.75 * 16px = 12px */ /* 0.5 * 16px = 8px */
+  /*
+   * Common.
+   */
+  /*
+   * Inputs.
+   */ /* Absolute zero with opacity. */ /* Davy's grey with 0.6 opacity. */ /* Light gray with 0.3 opacity on white bg. */ /* Old silver with 0.5 opacity on white bg. */ /* (1/8)em ~ 2px */ /* (1/16)em ~ 1px */ /* Font size is too big to use 1rem for extrasmall line-height */ /* 7px inside the form element label. */ /* 8px with the checkbox width of 19px */
+  /*
+   * Details.
+   */
+  /**
+   * Buttons.
+   */
+  /**
+   * jQuery.UI dropdown.
+   */ /* Light gray with 0.8 opacity. */ /* Text color with 0.1 opacity. */
+  /**
+   * Progress bar.
+   */
+  /**
+   * Tabledrag icon size.
+   */ /* 17px */
+  /**
+   * Ajax progress.
+   */
+  /**
+   * Breadcrumb.
+   */
+}
+
+:root { /* 20px */ /* 15px */ /* 10px */
+}
+
+.splitbutton {
+  position: relative;
+  display: inline-block;
+  max-width: 245px;
+  border-radius: 2px;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
+}
+
+.splitbutton__action--main.splitbutton__action--main,
+.splitbutton__toggle.splitbutton__toggle {
+  position: relative;
+  z-index: 3;
+  display: inline-block;
+  box-sizing: border-box;
+  margin: 0;
+  padding: calc(1rem - 1px) calc(1rem - 1px);
+  cursor: pointer;
+  text-align: left; /* LTR */
+  white-space: normal;
+  text-decoration: none;
+  color: #222330;
+  border: 1px solid transparent !important;
+  border-radius: 0;
+  background-color: #d4d4d8;
+  box-shadow: none;
+  font-size: 1rem;
+  font-weight: 700;
+  line-height: 1rem;
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  appearance: none;
+  -webkit-font-smoothing: antialiased;
+}
+
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main {
+  text-align: right;
+}
+
+.splitbutton--small .splitbutton__action--main,
+.splitbutton--small .splitbutton__toggle.splitbutton__toggle {
+  padding: calc(0.5rem - 1px) calc(1rem - 1px);
+  font-size: 0.79rem;
+}
+
+.splitbutton--extrasmall .splitbutton__action--main,
+.splitbutton--extrasmall .splitbutton__toggle.splitbutton__toggle {
+  padding: calc(0.25rem - 1px) calc(1rem - 1px);
+  font-size: 0.79rem;
+}
+
+/* Single splitbutton main item should look like a button. */
+
+.splitbutton--extrasmall .splitbutton__action--main:only-child {
+  padding: calc(0.25rem - 1px) calc(0.75rem - 1px);
+}
+
+.splitbutton__action--main.splitbutton__action--main:not(:focus),
+.splitbutton__toggle.splitbutton__toggle:not(:focus) {
+  box-shadow: none;
+}
+
+.splitbutton__action--main.splitbutton__action--main:hover,
+.splitbutton__toggle.splitbutton__toggle:hover {
+  text-decoration: none;
+  color: #222330;
+  background-color: #c2c3ca;
+}
+
+.splitbutton__action--main.splitbutton__action--main:hover:not(:focus),
+.splitbutton__toggle.splitbutton__toggle:hover:not(:focus) {
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
+}
+
+.splitbutton__action--main.splitbutton__action--main:focus,
+.splitbutton__toggle.splitbutton__toggle:focus {
+  z-index: 2;
+  text-decoration: none;
+}
+
+.splitbutton__action--main.splitbutton__action--main:active,
+.splitbutton__toggle.splitbutton__toggle:active {
+  color: #222330;
+  background-color: #adaeb3;
+}
+
+.splitbutton__main-items {
+  display: flex;
+}
+
+.splitbutton__action--main:first-child,
+.splitbutton__toggle:first-child {
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+
+.splitbutton__action--main:first-child + .splitbutton__action--main,
+.splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-left: 1px; /* LTR */
+}
+
+.splitbutton__action--main:last-child,
+.splitbutton__toggle:last-child {
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+
+[dir="rtl"] .splitbutton__action--main,
+[dir="rtl"] .splitbutton__toggle {
+  border-radius: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle {
+  margin: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle:first-child {
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__action--main,
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-right: 1px;
+  margin-left: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle:last-child {
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+
+.splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 3rem;
+  padding-right: 0;
+  padding-left: 0;
+  text-align: center;
+}
+
+.splitbutton--small .splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 2rem;
+  padding-right: 0;
+  padding-left: 0;
+}
+
+.splitbutton--extrasmall .splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 1.5rem;
+  padding-right: 0;
+  padding-left: 0;
+}
+
+.splitbutton__toggle-arrow {
+  position: relative;
+  display: inline-block;
+  width: 0.875rem;
+  height: 0.5625rem;
+}
+
+.splitbutton__toggle-arrow::before {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 100%;
+  content: "";
+  transform: translate(-50%, -50%) rotate(0);
+  background: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23222330'/%3E%3C/svg%3E") no-repeat center;
+  background-size: contain;
+}
+
+.splitbutton--small .splitbutton__toggle-arrow,
+.splitbutton--extrasmall .splitbutton__toggle-arrow {
+  width: 0.6875rem;
+}
+
+.splitbutton.open .splitbutton__toggle-arrow::before {
+  transform: translate(-50%, -50%) rotate(180deg);
+}
+
+.splitbutton__list {
+  z-index: 100;
+  box-sizing: border-box;
+  min-width: 100%;
+  max-width: 245px;
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  color: #545560;
+  border: 1px solid rgba(216, 217, 224, 0.8);
+  border-radius: 2px;
+  background: #fff;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+[dir="rtl"] .splitbutton__list {
+  margin: 0;
+  padding: 0;
+}
+
+.js .splitbutton__list:not(.open) {
+  position: absolute;
+  display: none;
+}
+
+.splitbutton__action.splitbutton__action--secondary {
+  position: relative;
+  display: block;
+  box-sizing: border-box;
+  min-width: 100%;
+  margin: 0; /* LTR */
+  padding: 0.875rem 1rem;
+  text-align: left; /* LTR */
+  white-space: normal;
+  text-decoration: none;
+  border: 0;
+  border-radius: 0;
+  box-shadow: none;
+  font-size: 1rem;
+  font-weight: normal;
+  line-height: 1.25rem;
+  -webkit-font-smoothing: unset;
+}
+
+[dir="rtl"] .splitbutton__action.splitbutton__action--secondary {
+  margin: 0;
+  text-align: right;
+}
+
+.splitbutton__action.splitbutton__action--secondary,
+.splitbutton__action.splitbutton__action--secondary:active {
+  color: #545560;
+  background: #fff;
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: 0.625rem 1rem;
+  font-size: 0.79rem;
+  line-height: 0.9375rem;
+}
+
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding-right: 0.75rem;
+  padding-left: 0.75rem;
+}
+
+.splitbutton__action.splitbutton__action--secondary:not(:focus) {
+  box-shadow: none;
+}
+
+.splitbutton__action.splitbutton__action--secondary:focus {
+  position: relative;
+  z-index: 1;
+}
+
+.splitbutton__action.splitbutton__action--secondary:hover {
+  color: #222330;
+  background: #f3f4f9;
+}
+
+.splitbutton__list-item:first-child .splitbutton__action {
+  border-top-left-radius: 1px;
+  border-top-right-radius: 1px;
+}
+
+.splitbutton__list-item:last-child .splitbutton__action {
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
diff --git a/core/themes/claro/css/components/splitbutton.pcss.css b/core/themes/claro/css/components/splitbutton.pcss.css
new file mode 100644
index 0000000000..b6070a01ca
--- /dev/null
+++ b/core/themes/claro/css/components/splitbutton.pcss.css
@@ -0,0 +1,280 @@
+/**
+ * @file
+ * Splitbutton styles.
+ */
+
+@import "../base/variables.pcss.css";
+
+:root {
+  --splitbutton-item-min-height: 3rem;
+  --splitbutton-item-line-height: 1.25rem; /* 20px */
+  --splitbutton-item-padding-vertical: calc((var(--splitbutton-item-min-height) - var(--splitbutton-item-line-height)) / 2);
+  --splitbutton-item--small-font-size: var(--font-size-xs);
+  --splitbutton-item--small-line-height: 0.9375rem; /* 15px */
+  --splitbutton-item--small-padding-vertical: 0.625rem; /* 10px */
+}
+
+.splitbutton {
+  position: relative;
+  display: inline-block;
+  max-width: 245px;
+  border-radius: var(--button-border-radius-size);
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
+}
+
+.splitbutton__action--main.splitbutton__action--main,
+.splitbutton__toggle.splitbutton__toggle {
+  position: relative;
+  z-index: 3;
+  display: inline-block;
+  box-sizing: border-box;
+  margin: 0;
+  padding: calc(var(--space-m) - 1px) calc(var(--space-m) - 1px);
+  cursor: pointer;
+  text-align: left; /* LTR */
+  white-space: normal;
+  text-decoration: none;
+  color: var(--button-fg-color);
+  border: 1px solid transparent !important;
+  border-radius: 0;
+  background-color: var(--button-bg-color);
+  box-shadow: none;
+  font-size: var(--font-size-base);
+  font-weight: 700;
+  line-height: 1rem;
+  appearance: none;
+  -webkit-font-smoothing: antialiased;
+}
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main {
+  text-align: right;
+}
+
+.splitbutton--small .splitbutton__action--main,
+.splitbutton--small .splitbutton__toggle.splitbutton__toggle {
+  padding: calc(var(--space-xs) - 1px) calc(var(--space-m) - 1px);
+  font-size: var(--font-size-xs);
+}
+
+.splitbutton--extrasmall .splitbutton__action--main,
+.splitbutton--extrasmall .splitbutton__toggle.splitbutton__toggle {
+  padding: calc(calc(var(--space-xs) / 2) - 1px) calc(var(--space-m) - 1px);
+  font-size: var(--font-size-xs);
+}
+
+/* Single splitbutton main item should look like a button. */
+.splitbutton--extrasmall .splitbutton__action--main:only-child {
+  padding: calc(calc(var(--space-xs) / 2) - 1px) calc(var(--space-s) - 1px);
+}
+
+.splitbutton__action--main.splitbutton__action--main:not(:focus),
+.splitbutton__toggle.splitbutton__toggle:not(:focus) {
+  box-shadow: none;
+}
+.splitbutton__action--main.splitbutton__action--main:hover,
+.splitbutton__toggle.splitbutton__toggle:hover {
+  text-decoration: none;
+  color: var(--button-fg-color);
+  background-color: var(--button--hover-bg-color);
+}
+
+.splitbutton__action--main.splitbutton__action--main:hover:not(:focus),
+.splitbutton__toggle.splitbutton__toggle:hover:not(:focus) {
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
+}
+
+.splitbutton__action--main.splitbutton__action--main:focus,
+.splitbutton__toggle.splitbutton__toggle:focus {
+  z-index: 2;
+  text-decoration: none;
+}
+
+.splitbutton__action--main.splitbutton__action--main:active,
+.splitbutton__toggle.splitbutton__toggle:active {
+  color: var(--button-fg-color);
+  background-color: var(--button--active-bg-color);
+}
+
+.splitbutton__main-items {
+  display: flex;
+}
+
+.splitbutton__action--main:first-child,
+.splitbutton__toggle:first-child {
+  border-top-left-radius: var(--button-border-radius-size);
+  border-bottom-left-radius: var(--button-border-radius-size);
+}
+
+.splitbutton__action--main:first-child + .splitbutton__action--main,
+.splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-left: 1px; /* LTR */
+}
+
+.splitbutton__action--main:last-child,
+.splitbutton__toggle:last-child {
+  border-top-right-radius: var(--button-border-radius-size);
+  border-bottom-right-radius: var(--button-border-radius-size);
+}
+
+[dir="rtl"] .splitbutton__action--main,
+[dir="rtl"] .splitbutton__toggle {
+  border-radius: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle {
+  margin: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle:first-child {
+  border-top-right-radius: var(--button-border-radius-size);
+  border-bottom-right-radius: var(--button-border-radius-size);
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__action--main,
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-right: 1px;
+  margin-left: 0;
+}
+
+[dir="rtl"] .splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle:last-child {
+  border-top-left-radius: var(--button-border-radius-size);
+  border-bottom-left-radius: var(--button-border-radius-size);
+}
+
+.splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 3rem;
+  padding-right: 0;
+  padding-left: 0;
+  text-align: center;
+}
+
+.splitbutton--small .splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 2rem;
+  padding-right: 0;
+  padding-left: 0;
+}
+
+.splitbutton--extrasmall .splitbutton__toggle.splitbutton__toggle--no-label {
+  width: 1.5rem;
+  padding-right: 0;
+  padding-left: 0;
+}
+
+.splitbutton__toggle-arrow {
+  position: relative;
+  display: inline-block;
+  width: 0.875rem;
+  height: 0.5625rem;
+}
+
+.splitbutton__toggle-arrow::before {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 100%;
+  content: "";
+  transform: translate(-50%, -50%) rotate(0);
+  background: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23222330'/%3E%3C/svg%3E") no-repeat center;
+  background-size: contain;
+}
+
+.splitbutton--small .splitbutton__toggle-arrow,
+.splitbutton--extrasmall .splitbutton__toggle-arrow {
+  width: 0.6875rem;
+}
+
+.splitbutton.open .splitbutton__toggle-arrow::before {
+  transform: translate(-50%, -50%) rotate(180deg);
+}
+
+.splitbutton__list {
+  z-index: 100;
+  box-sizing: border-box;
+  min-width: 100%;
+  max-width: 245px;
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  color: var(--color-davysgrey);
+  border: 1px solid var(--details-border-color);
+  border-radius: 2px;
+  background: var(--color-white);
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+[dir="rtl"] .splitbutton__list {
+  margin: 0;
+  padding: 0;
+}
+
+.js .splitbutton__list:not(.open) {
+  position: absolute;
+  display: none;
+}
+
+.splitbutton__action.splitbutton__action--secondary {
+  position: relative;
+  display: block;
+  box-sizing: border-box;
+  min-width: 100%;
+  margin: 0; /* LTR */
+  padding: calc(var(--splitbutton-item-padding-vertical)) var(--space-m);
+  text-align: left; /* LTR */
+  white-space: normal;
+  text-decoration: none;
+  border: 0;
+  border-radius: 0;
+  box-shadow: none;
+  font-size: var(--font-size-base);
+  font-weight: normal;
+  line-height: var(--splitbutton-item-line-height);
+  -webkit-font-smoothing: unset;
+}
+[dir="rtl"] .splitbutton__action.splitbutton__action--secondary {
+  margin: 0;
+  text-align: right;
+}
+
+.splitbutton__action.splitbutton__action--secondary,
+.splitbutton__action.splitbutton__action--secondary:active {
+  color: var(--color-davysgrey);
+  background: var(--color-white);
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: calc(var(--splitbutton-item--small-padding-vertical)) var(--space-m);
+  font-size: var(--splitbutton-item--small-font-size);
+  line-height: var(--splitbutton-item--small-line-height);
+}
+
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding-right: var(--space-s);
+  padding-left: var(--space-s);
+}
+
+.splitbutton__action.splitbutton__action--secondary:not(:focus) {
+  box-shadow: none;
+}
+
+.splitbutton__action.splitbutton__action--secondary:focus {
+  position: relative;
+  z-index: 1;
+}
+
+.splitbutton__action.splitbutton__action--secondary:hover {
+  color: var(--color-text);
+  background: var(--color-whitesmoke);
+}
+
+.splitbutton__list-item:first-child .splitbutton__action {
+  border-top-left-radius: 1px;
+  border-top-right-radius: 1px;
+}
+
+.splitbutton__list-item:last-child .splitbutton__action {
+  border-bottom-right-radius: 1px;
+  border-bottom-left-radius: 1px;
+}
diff --git a/core/themes/claro/css/components/views-ui.css b/core/themes/claro/css/components/views-ui.css
index fcf73acf54..5552b257e0 100644
--- a/core/themes/claro/css/components/views-ui.css
+++ b/core/themes/claro/css/components/views-ui.css
@@ -9,6 +9,50 @@
  * Views styling
  */
 
+:root {
+  /*
+   * Color Palette.
+   */
+  /* Secondary. */
+  /* Variations. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 10% darker than base. */ /* 20% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */ /* 5% darker than base. */ /* 10% darker than base. */
+  /*
+   * Base.
+   */
+  /*
+   * Typography.
+   */ /* 1rem = 16px if font root is 100% ands browser defaults are used. */ /* ~32px */ /* ~29px */ /* ~26px */ /* ~23px */ /* ~20px */ /* 18px */ /* ~14px */ /* ~13px */ /* ~11px */
+  /**
+   * Spaces.
+   */ /* 3 * 16px = 48px */ /* 1.5 * 16px = 24px */ /* 1 * 16px = 16px */ /* 0.75 * 16px = 12px */ /* 0.5 * 16px = 8px */
+  /*
+   * Common.
+   */
+  /*
+   * Inputs.
+   */ /* Absolute zero with opacity. */ /* Davy's grey with 0.6 opacity. */ /* Light gray with 0.3 opacity on white bg. */ /* Old silver with 0.5 opacity on white bg. */ /* (1/8)em ~ 2px */ /* (1/16)em ~ 1px */ /* Font size is too big to use 1rem for extrasmall line-height */ /* 7px inside the form element label. */ /* 8px with the checkbox width of 19px */
+  /*
+   * Details.
+   */
+  /**
+   * Buttons.
+   */
+  /**
+   * jQuery.UI dropdown.
+   */ /* Light gray with 0.8 opacity. */ /* Text color with 0.1 opacity. */
+  /**
+   * Progress bar.
+   */
+  /**
+   * Tabledrag icon size.
+   */ /* 17px */
+  /**
+   * Ajax progress.
+   */
+  /**
+   * Breadcrumb.
+   */
+}
+
 /* @group Forms */
 
 /**
@@ -90,61 +134,6 @@ details.fieldset-no-legend {
 
 /* @end */
 
-/* @group Lists */
-
-.views-admin ul.secondary,
-.views-admin .item-list ul {
-  margin: 0;
-  padding: 0;
-}
-
-.views-displays ul.secondary li a,
-.views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
-  padding: 2px 7px 3px;
-}
-
-.views-displays ul.secondary li a {
-  color: #0074bd;
-}
-
-.views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
-  border: 1px solid transparent;
-}
-
-.views-admin .links li {
-  padding-right: 0; /* LTR */
-}
-
-[dir="rtl"] .views-admin .links li {
-  padding-left: 0;
-}
-
-.views-admin .button .links li {
-  padding-right: 12px; /* LTR */
-}
-
-[dir="rtl"] .views-admin .button .links li {
-  padding-left: 12px;
-}
-
-.views-display-top ul.secondary {
-  float: left; /* LTR */
-  background-color: transparent;
-}
-
-[dir="rtl"] .views-display-top ul.secondary {
-  float: right;
-}
-
-.views-display-top .secondary .action-list li {
-  float: none;
-  margin: 0;
-}
-
-/* @end */
-
 /* @group Tables */
 
 .views-ui-rearrange-filter-form table td,
@@ -172,235 +161,117 @@ details.fieldset-no-legend {
  */
 
 .views-tabs {
-  overflow: visible;
-  margin: 0 200px 0 0; /* LTR */
+  flex-grow: 1;
+  margin: 0; /* LTR */
   padding: 0;
   list-style: none;
   text-align: left; /* LTR */
-  border-bottom: 0 none;
 }
 
 [dir="rtl"] .views-tabs {
-  margin-right: 0;
-  margin-left: 200px;
+  margin: 0;
   text-align: right;
 }
 
 .views-tabs > li {
   float: left; /* LTR */
   padding: 0;
-  border-right: 0 none; /* LTR */
+  border: 0;
 }
 
 [dir="rtl"] .views-tabs > li {
   float: right;
-  border-right: 1px solid #bfbfbf;
-  border-left: 0 none;
-}
-
-.views-tabs .open > a {
-  position: relative;
-  z-index: 51;
 }
 
 .views-tabs .views-display-deleted-link {
   text-decoration: line-through;
 }
 
-.views-tabs .add {
-  position: relative;
-}
-
-.views-tabs .action-list {
-  position: absolute;
-  z-index: 50;
-  top: 23px;
-  left: 0; /* LTR */
-  margin: 0;
-}
-
-[dir="rtl"] .views-tabs .action-list {
-  right: 0;
-  left: auto;
-}
-
-.views-tabs .action-list li {
-  display: block;
-}
-
 .views-tab a:hover > .icon.add {
   background-position: center -25px;
 }
 
-.views-tab .open > a {
-  border-radius: 7px 7px 0 0;
-}
-
-.views-tab .open > a:hover,
-.views-tab .open > a:focus {
-  color: #008bcb;
-  background-color: #f1f1f1;
-}
-
-.views-tab .action-list li:first-child {
-  border-radius: 0 7px 0 0; /* LTR */
-}
-
-[dir="rtl"] .views-tab .action-list li:first-child {
-  border-radius: 7px 0 0 0;
-}
-
-.views-tab .action-list li:last-child {
-  border-radius: 0 0 7px 7px;
-}
-
-.views-tab .action-list input.form-submit {
-  color: #008bcb;
-}
-
-.views-tabs li,
-.views-tabs li.is-active {
+.views-tabs > li,
+.views-tabs > li.is-active {
   width: auto;
   padding: 0;
   border: 0;
   background: transparent;
 }
 
-.views-tabs li.add ul.action-list li {
-  margin: 0;
-}
-
-.views-tabs li {
-  margin: 0 5px 5px 6px; /* LTR */
+.views-tabs > li,
+.views-ui-views-extra-actions {
+  margin: 2px 5px 2px 6px; /* LTR */
 }
 
-[dir="rtl"] .views-tabs li {
+[dir="rtl"] .views-tabs > li {
   margin-right: 6px;
   margin-left: 5px;
 }
 
-.views-tabs li + li {
-  border-top: 0;
-}
-
-.views-tabs li:hover {
+.views-tabs > li:hover {
   padding-left: 0; /* LTR */
-  border: 0;
 }
 
-[dir="rtl"] .views-tabs li:hover {
+[dir="rtl"] .views-tabs > li:hover {
   padding-right: 0;
 }
 
-.views-tabs a {
+.views-tabs > li > a,
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle {
   display: inline-block;
   padding: 3px 7px;
+  text-decoration: none;
+  color: #003cc5;
   border: 1px solid #cbcbcb;
   border-radius: 7px;
+  background: #fff;
   font-size: small;
+  font-weight: normal;
   line-height: 1.3333;
+  -webkit-font-smoothing: unset;
 }
 
-/* Display a red border if the display doesn't validate. */
-
-.views-tabs li.is-active a.is-active.error,
-.views-tabs .error {
-  padding: 1px 6px;
-  border: 2px solid #ed541d;
-}
-
-.views-tabs a:focus {
-  outline: none;
-}
-
-.views-tabs li a {
-  text-decoration: none;
-  background-color: #fff;
-}
-
-.views-tabs li a:hover,
-.views-tabs li.is-active a,
-.views-tabs li.is-active a.is-active {
-  color: #fff;
-  background-color: #555;
-}
-
-.views-tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-
-.views-tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle {
+  border-color: #cbcbcb !important;
 }
 
-.views-tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-
-.views-tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-
-.views-tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-
-.views-tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-
-.views-tabs .action-list input.form-submit:hover {
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle:hover:not(:focus) {
   box-shadow: none;
 }
 
-.views-tabs .action-list li:hover {
-  background-color: #ddd;
+.views-ui-views-display-add-actions .splitbutton__toggle-arrow::before {
+  width: 0.6875rem;
+  background-image: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23003cc5'/%3E%3C/svg%3E");
 }
 
-.views-tabs a:hover > .icon.add {
-  background-position: center -25px;
-}
+/* Display a red border if the display doesn't validate. */
 
-.views-tabs .open a:hover > .icon.add {
-  background-position: center 3px;
+.views-tabs > li.is-active > a.is-active.error,
+.views-tabs > li > .error {
+  padding: 1px 6px;
+  border: 2px solid #ed541d;
 }
 
-/* @end */
-
-/* @group Attachment buckets
- *
- * These are the individual "buckets," or boxes, inside the display settings area
- */
-
-.views-ui-display-tab-bucket h3 {
-  text-transform: uppercase;
+.views-tabs > li > a:focus {
+  outline: none;
 }
 
-.views-ui-display-tab-bucket .links {
-  padding: 2px 6px 4px;
+.views-tabs > li > a:hover,
+.views-tabs > li.is-active > a,
+.views-tabs > li.is-active > a.is-active,
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle:hover {
+  color: #fff;
+  background-color: #555;
 }
 
-.views-ui-display-tab-bucket .links li + li {
-  margin-left: 3px; /* LTR */
+.views-ui-views-display-add-actions .splitbutton__toggle:hover .splitbutton__toggle-arrow::before {
+  background-image: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23fff'/%3E%3C/svg%3E");
 }
 
-[dir="rtl"] .views-ui-display-tab-bucket .links li + li {
-  margin-right: 3px;
-  margin-left: 0;
+.splitbutton.views-ui-views-display-add-actions {
+  border: 0;
+  box-shadow: none;
 }
 
 /* @end */
diff --git a/core/themes/claro/css/components/views-ui.pcss.css b/core/themes/claro/css/components/views-ui.pcss.css
index 4d7c12a352..73c48c34b2 100644
--- a/core/themes/claro/css/components/views-ui.pcss.css
+++ b/core/themes/claro/css/components/views-ui.pcss.css
@@ -2,6 +2,8 @@
  * Views styling
  */
 
+@import "../base/variables.pcss.css";
+
 /* @group Forms */
 
 /**
@@ -77,58 +79,6 @@ details.fieldset-no-legend {
 
 /* @end */
 
-/* @group Lists */
-
-.views-admin ul.secondary,
-.views-admin .item-list ul {
-  margin: 0;
-  padding: 0;
-}
-
-.views-displays ul.secondary li a,
-.views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
-  padding: 2px 7px 3px;
-}
-
-.views-displays ul.secondary li a {
-  color: #0074bd;
-}
-
-.views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
-  border: 1px solid transparent;
-}
-
-.views-admin .links li {
-  padding-right: 0; /* LTR */
-}
-[dir="rtl"] .views-admin .links li {
-  padding-left: 0;
-}
-
-.views-admin .button .links li {
-  padding-right: 12px; /* LTR */
-}
-[dir="rtl"] .views-admin .button .links li {
-  padding-left: 12px;
-}
-
-.views-display-top ul.secondary {
-  float: left; /* LTR */
-  background-color: transparent;
-}
-[dir="rtl"] .views-display-top ul.secondary {
-  float: right;
-}
-
-.views-display-top .secondary .action-list li {
-  float: none;
-  margin: 0;
-}
-
-/* @end */
-
 /* @group Tables */
 
 .views-ui-rearrange-filter-form table td,
@@ -156,203 +106,105 @@ details.fieldset-no-legend {
  */
 
 .views-tabs {
-  overflow: visible;
-  margin: 0 200px 0 0; /* LTR */
+  flex-grow: 1;
+  margin: 0; /* LTR */
   padding: 0;
   list-style: none;
   text-align: left; /* LTR */
-  border-bottom: 0 none;
 }
 [dir="rtl"] .views-tabs {
-  margin-right: 0;
-  margin-left: 200px;
+  margin: 0;
   text-align: right;
 }
 .views-tabs > li {
   float: left; /* LTR */
   padding: 0;
-  border-right: 0 none; /* LTR */
+  border: 0;
 }
 [dir="rtl"] .views-tabs > li {
   float: right;
-  border-right: 1px solid #bfbfbf;
-  border-left: 0 none;
-}
-.views-tabs .open > a {
-  position: relative;
-  z-index: 51;
 }
 .views-tabs .views-display-deleted-link {
   text-decoration: line-through;
 }
-.views-tabs .add {
-  position: relative;
-}
-.views-tabs .action-list {
-  position: absolute;
-  z-index: 50;
-  top: 23px;
-  left: 0; /* LTR */
-  margin: 0;
-}
-[dir="rtl"] .views-tabs .action-list {
-  right: 0;
-  left: auto;
-}
-.views-tabs .action-list li {
-  display: block;
-}
 
 .views-tab a:hover > .icon.add {
   background-position: center -25px;
 }
 
-.views-tab .open > a {
-  border-radius: 7px 7px 0 0;
-}
-
-.views-tab .open > a:hover,
-.views-tab .open > a:focus {
-  color: #008bcb;
-  background-color: #f1f1f1;
-}
-
-.views-tab .action-list li:first-child {
-  border-radius: 0 7px 0 0; /* LTR */
-}
-[dir="rtl"] .views-tab .action-list li:first-child {
-  border-radius: 7px 0 0 0;
-}
-
-.views-tab .action-list li:last-child {
-  border-radius: 0 0 7px 7px;
-}
-
-.views-tab .action-list input.form-submit {
-  color: #008bcb;
-}
-
-.views-tabs li,
-.views-tabs li.is-active {
+.views-tabs > li,
+.views-tabs > li.is-active {
   width: auto;
   padding: 0;
   border: 0;
   background: transparent;
 }
-.views-tabs li.add ul.action-list li {
-  margin: 0;
-}
-.views-tabs li {
-  margin: 0 5px 5px 6px; /* LTR */
+.views-tabs > li,
+.views-ui-views-extra-actions {
+  margin: 2px 5px 2px 6px; /* LTR */
 }
-[dir="rtl"] .views-tabs li {
+
+[dir="rtl"] .views-tabs > li {
   margin-right: 6px;
   margin-left: 5px;
 }
-.views-tabs li + li {
-  border-top: 0;
-}
-.views-tabs li:hover {
+.views-tabs > li:hover {
   padding-left: 0; /* LTR */
-  border: 0;
 }
-[dir="rtl"] .views-tabs li:hover {
+[dir="rtl"] .views-tabs > li:hover {
   padding-right: 0;
 }
-.views-tabs a {
+.views-tabs > li > a,
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle {
   display: inline-block;
   padding: 3px 7px;
+  text-decoration: none;
+  color: var(--color-absolutezero);
   border: 1px solid #cbcbcb;
   border-radius: 7px;
+  background: var(--color-white);
   font-size: small;
+  font-weight: normal;
   line-height: 1.3333;
+  -webkit-font-smoothing: unset;
+}
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle {
+  border-color: #cbcbcb !important;
+}
+
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle:hover:not(:focus) {
+  box-shadow: none;
+}
+
+.views-ui-views-display-add-actions .splitbutton__toggle-arrow::before {
+  width: 0.6875rem;
+  background-image: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23003cc5'/%3E%3C/svg%3E");
 }
 
 /* Display a red border if the display doesn't validate. */
-.views-tabs li.is-active a.is-active.error,
-.views-tabs .error {
+.views-tabs > li.is-active > a.is-active.error,
+.views-tabs > li > .error {
   padding: 1px 6px;
   border: 2px solid #ed541d;
 }
-.views-tabs a:focus {
+.views-tabs > li > a:focus {
   outline: none;
 }
-.views-tabs li a {
-  text-decoration: none;
-  background-color: #fff;
-}
-.views-tabs li a:hover,
-.views-tabs li.is-active a,
-.views-tabs li.is-active a.is-active {
+.views-tabs > li > a:hover,
+.views-tabs > li.is-active > a,
+.views-tabs > li.is-active > a.is-active,
+.splitbutton.views-ui-views-display-add-actions .splitbutton__toggle:hover {
   color: #fff;
   background-color: #555;
 }
-.views-tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-.views-tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
-}
-.views-tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-.views-tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-.views-tabs .action-list input.form-submit:hover {
-  box-shadow: none;
-}
-.views-tabs .action-list li:hover {
-  background-color: #ddd;
-}
 
-.views-tabs a:hover > .icon.add {
-  background-position: center -25px;
+.views-ui-views-display-add-actions .splitbutton__toggle:hover .splitbutton__toggle-arrow::before {
+  background-image: url("data:image/svg+xml,%3Csvg width='14' height='9' viewBox='0 0 14 9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.2384999,1.9384769 1.646703,0.5166019 7.0002189,5.8193359 12.353735,0.5166019 13.761938,1.9384769 7.0002189,8.635742Z' fill='%23fff'/%3E%3C/svg%3E");
 }
-.views-tabs .open a:hover > .icon.add {
-  background-position: center 3px;
-}
-
-/* @end */
 
-/* @group Attachment buckets
- *
- * These are the individual "buckets," or boxes, inside the display settings area
- */
-
-.views-ui-display-tab-bucket h3 {
-  text-transform: uppercase;
-}
-
-.views-ui-display-tab-bucket .links {
-  padding: 2px 6px 4px;
-}
-
-.views-ui-display-tab-bucket .links li + li {
-  margin-left: 3px; /* LTR */
-}
-[dir="rtl"] .views-ui-display-tab-bucket .links li + li {
-  margin-right: 3px;
-  margin-left: 0;
+.splitbutton.views-ui-views-display-add-actions {
+  border: 0;
+  box-shadow: none;
 }
 
 /* @end */
diff --git a/core/themes/claro/css/theme/views_ui.admin.theme.css b/core/themes/claro/css/theme/views_ui.admin.theme.css
index 0f592906e1..b053fb4a34 100644
--- a/core/themes/claro/css/theme/views_ui.admin.theme.css
+++ b/core/themes/claro/css/theme/views_ui.admin.theme.css
@@ -135,14 +135,6 @@
   background-position: center -111px, right top;
 }
 
-.views-displays .tabs a:hover > .icon.add {
-  background-position: center -25px;
-}
-
-.views-displays .tabs .open a:hover > .icon.add {
-  background-position: center 3px;
-}
-
 details.box-padding {
   border: none;
 }
@@ -372,41 +364,14 @@ td.group-title {
 }
 
 .views-display-top {
-  position: relative;
-  padding: 8px 8px 3px;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  padding: 3px 8px;
   border-bottom: 1px solid #ccc;
   background-color: #e1e2dc;
 }
 
-.views-display-top .tabs {
-  margin-right: 18em; /* LTR */
-}
-
-[dir="rtl"] .views-display-top .tabs {
-  margin-right: 0;
-  margin-left: 18em;
-}
-
-.views-display-top .tabs > li {
-  margin-right: 6px; /* LTR */
-  padding-left: 0; /* LTR */
-}
-
-[dir="rtl"] .views-display-top .tabs > li {
-  margin-right: 0.3em;
-  margin-left: 6px;
-  padding-right: 0;
-}
-
-.views-display-top .tabs > li:last-child {
-  margin-right: 0; /* LTR */
-}
-
-[dir="rtl"] .views-display-top .tabs > li:last-child {
-  margin-right: 0.3em;
-  margin-left: 0;
-}
-
 .form-edit .form-actions {
   margin-top: 0;
   padding: 8px 12px;
@@ -416,141 +381,10 @@ td.group-title {
   background-color: #e1e2dc;
 }
 
-.views-displays .tabs.secondary {
-  margin-right: 200px; /* LTR */
-  border: 0;
-}
-
-[dir="rtl"] .views-displays .tabs.secondary {
-  margin-right: 0;
-  margin-left: 200px;
-}
-
-.views-displays .tabs.secondary li,
-.views-displays .tabs.secondary li.is-active {
-  width: auto;
-  padding: 0;
-  border: 0;
-  background: transparent;
-}
-
-.views-displays .tabs li.add ul.action-list li {
-  margin: 0;
-}
-
-.views-displays .tabs.secondary li {
-  margin: 0 5px 5px 6px; /* LTR */
-}
-
-[dir="rtl"] .views-displays .tabs.secondary li {
-  margin-right: 6px;
-  margin-left: 5px;
-}
-
-.views-displays .tabs.secondary .tabs__tab + .tabs__tab {
-  border-top: 0;
-}
-
-.views-displays .tabs li.tabs__tab:hover {
-  padding-left: 0; /* LTR */
-  border: 0;
-}
-
-[dir="rtl"] .views-displays .tabs li.tabs__tab:hover {
-  padding-right: 0;
-}
-
-.views-displays .tabs.secondary a {
-  display: inline-block;
-  padding: 3px 7px;
-  border: 1px solid #cbcbcb;
-  border-radius: 7px;
-  font-size: small;
-  line-height: 1.3333;
-}
-
-/* Display a red border if the display doesn't validate. */
-
-.views-displays .tabs li.is-active a.is-active.error,
-.views-displays .tabs .error {
-  padding: 1px 6px;
-  border: 2px solid #ed541d;
-}
-
-.views-displays .tabs a:focus {
-  outline: none;
-}
-
-.views-displays .tabs.secondary li a {
-  background-color: #fff;
-}
-
-.views-displays .tabs li a:hover,
-.views-displays .tabs li.is-active a,
-.views-displays .tabs li.is-active a.is-active {
-  color: #fff;
-  background-color: #555;
-}
-
-.views-displays .tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-
-.views-displays .tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
-}
-
-.views-displays .tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-
-.views-displays .tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-
-.views-displays .tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-
-.views-displays .tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-
-.views-displays .tabs .action-list input.form-submit:hover {
-  box-shadow: none;
-}
-
-.views-displays .tabs .action-list li:hover {
-  background-color: #ddd;
-}
-
 .edit-display-settings {
   margin: 12px 12px 0 12px;
 }
 
-.edit-display-settings-top.views-ui-display-tab-bucket {
-  position: relative;
-  margin: 0 0 15px 0;
-  padding-top: 4px;
-  padding-bottom: 4px;
-  border: 1px solid #f3f3f3;
-  line-height: 20px;
-}
-
 .views-display-column {
   border: 1px solid #f3f3f3;
 }
@@ -627,13 +461,32 @@ td.group-title {
   border-top: medium none;
 }
 
-.views-ui-display-tab-bucket__title,
 .views-ui-display-tab-bucket > .views-display-setting {
-  padding: 3px 6px 4px;
+  padding: 2px 6px 4px;
+}
+
+.views-ui-display-tab-actions.views-ui-display-tab-bucket {
+  position: relative;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin-bottom: 15px;
+  padding-bottom: 4px;
+  border: 1px solid #f3f3f3;
+}
+
+.views-ui-display-tab-bucket__header {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  justify-content: flex-end;
+  padding: 1px 6px 6px;
 }
 
 .views-ui-display-tab-bucket__title {
+  flex-grow: 1;
   margin: 0;
+  text-transform: uppercase;
   font-size: small;
 }
 
@@ -685,7 +538,17 @@ td.group-title {
 }
 
 .views-ui-display-tab-actions.views-ui-display-tab-bucket .views-display-setting {
-  background-color: transparent;
+  flex-grow: 1;
+  background: transparent;
+}
+
+.views-ui-views-tab-bucket-actions {
+  margin-right: 5px; /* LTR */
+}
+
+[dir="rtl"] .views-ui-views-tab-bucket-actions {
+  margin-right: 0;
+  margin-left: 5px;
 }
 
 .views-ui-display-tab-bucket .views-group-text {
@@ -695,6 +558,7 @@ td.group-title {
 
 .views-display-setting .label {
   margin-right: 3px; /* LTR */
+  font-weight: bold;
 }
 
 [dir="rtl"] .views-display-setting .label {
@@ -954,40 +818,6 @@ td.group-title {
   line-height: 1.4555;
 }
 
-.js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  position: absolute;
-  z-index: 2;
-  top: -1px;
-  right: -5px; /* LTR */
-}
-
-[dir="rtl"].js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  right: auto;
-  left: -5px;
-}
-
-.views-display-top .dropbutton-wrapper {
-  position: absolute;
-  top: 5px;
-  right: 4px; /* LTR */
-}
-
-[dir="rtl"] .views-display-top .dropbutton-wrapper {
-  right: auto;
-  left: 4px;
-}
-
-.views-ui-display-tab-bucket .dropbutton-wrapper {
-  position: absolute;
-  top: 3px;
-  right: 3px; /* LTR */
-}
-
-[dir="rtl"] .views-ui-display-tab-bucket .dropbutton-wrapper {
-  right: auto;
-  left: 3px;
-}
-
 .views-list-section {
   margin-bottom: 2em;
 }
diff --git a/core/themes/claro/css/theme/views_ui.admin.theme.pcss.css b/core/themes/claro/css/theme/views_ui.admin.theme.pcss.css
index 6b1909cdea..8d814fc41b 100644
--- a/core/themes/claro/css/theme/views_ui.admin.theme.pcss.css
+++ b/core/themes/claro/css/theme/views_ui.admin.theme.pcss.css
@@ -102,12 +102,6 @@
 [dir="rtl"] .views-admin a.icon.rearrange {
   background-position: center -111px, right top;
 }
-.views-displays .tabs a:hover > .icon.add {
-  background-position: center -25px;
-}
-.views-displays .tabs .open a:hover > .icon.add {
-  background-position: center 3px;
-}
 details.box-padding {
   border: none;
 }
@@ -295,34 +289,14 @@ td.group-title {
   border: 1px solid #ccc;
 }
 .views-display-top {
-  position: relative;
-  padding: 8px 8px 3px;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  padding: 3px 8px;
   border-bottom: 1px solid #ccc;
   background-color: #e1e2dc;
 }
-.views-display-top .tabs {
-  margin-right: 18em; /* LTR */
-}
-[dir="rtl"] .views-display-top .tabs {
-  margin-right: 0;
-  margin-left: 18em;
-}
-.views-display-top .tabs > li {
-  margin-right: 6px; /* LTR */
-  padding-left: 0; /* LTR */
-}
-[dir="rtl"] .views-display-top .tabs > li {
-  margin-right: 0.3em;
-  margin-left: 6px;
-  padding-right: 0;
-}
-.views-display-top .tabs > li:last-child {
-  margin-right: 0; /* LTR */
-}
-[dir="rtl"] .views-display-top .tabs > li:last-child {
-  margin-right: 0.3em;
-  margin-left: 0;
-}
+
 .form-edit .form-actions {
   margin-top: 0;
   padding: 8px 12px;
@@ -331,116 +305,9 @@ td.group-title {
   border-left: 1px solid #ccc;
   background-color: #e1e2dc;
 }
-.views-displays .tabs.secondary {
-  margin-right: 200px; /* LTR */
-  border: 0;
-}
-[dir="rtl"] .views-displays .tabs.secondary {
-  margin-right: 0;
-  margin-left: 200px;
-}
-.views-displays .tabs.secondary li,
-.views-displays .tabs.secondary li.is-active {
-  width: auto;
-  padding: 0;
-  border: 0;
-  background: transparent;
-}
-.views-displays .tabs li.add ul.action-list li {
-  margin: 0;
-}
-.views-displays .tabs.secondary li {
-  margin: 0 5px 5px 6px; /* LTR */
-}
-[dir="rtl"] .views-displays .tabs.secondary li {
-  margin-right: 6px;
-  margin-left: 5px;
-}
-.views-displays .tabs.secondary .tabs__tab + .tabs__tab {
-  border-top: 0;
-}
-.views-displays .tabs li.tabs__tab:hover {
-  padding-left: 0; /* LTR */
-  border: 0;
-}
-[dir="rtl"] .views-displays .tabs li.tabs__tab:hover {
-  padding-right: 0;
-}
-.views-displays .tabs.secondary a {
-  display: inline-block;
-  padding: 3px 7px;
-  border: 1px solid #cbcbcb;
-  border-radius: 7px;
-  font-size: small;
-  line-height: 1.3333;
-}
-
-/* Display a red border if the display doesn't validate. */
-.views-displays .tabs li.is-active a.is-active.error,
-.views-displays .tabs .error {
-  padding: 1px 6px;
-  border: 2px solid #ed541d;
-}
-.views-displays .tabs a:focus {
-  outline: none;
-}
-.views-displays .tabs.secondary li a {
-  background-color: #fff;
-}
-.views-displays .tabs li a:hover,
-.views-displays .tabs li.is-active a,
-.views-displays .tabs li.is-active a.is-active {
-  color: #fff;
-  background-color: #555;
-}
-.views-displays .tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-.views-displays .tabs .action-list input.form-submit:hover {
-  box-shadow: none;
-}
-.views-displays .tabs .action-list li:hover {
-  background-color: #ddd;
-}
 .edit-display-settings {
   margin: 12px 12px 0 12px;
 }
-.edit-display-settings-top.views-ui-display-tab-bucket {
-  position: relative;
-  margin: 0 0 15px 0;
-  padding-top: 4px;
-  padding-bottom: 4px;
-  border: 1px solid #f3f3f3;
-  line-height: 20px;
-}
 .views-display-column {
   border: 1px solid #f3f3f3;
 }
@@ -504,12 +371,32 @@ td.group-title {
 .views-ui-display-tab-bucket + .views-ui-display-tab-bucket {
   border-top: medium none;
 }
-.views-ui-display-tab-bucket__title,
 .views-ui-display-tab-bucket > .views-display-setting {
-  padding: 3px 6px 4px;
+  padding: 2px 6px 4px;
 }
+
+.views-ui-display-tab-actions.views-ui-display-tab-bucket {
+  position: relative;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin-bottom: 15px;
+  padding-bottom: 4px;
+  border: 1px solid #f3f3f3;
+}
+
+.views-ui-display-tab-bucket__header {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  justify-content: flex-end;
+  padding: 1px 6px 6px;
+}
+
 .views-ui-display-tab-bucket__title {
+  flex-grow: 1;
   margin: 0;
+  text-transform: uppercase;
   font-size: small;
 }
 .views-ui-display-tab-bucket.access {
@@ -553,14 +440,25 @@ td.group-title {
   background-color: #f3f5ee;
 }
 .views-ui-display-tab-actions.views-ui-display-tab-bucket .views-display-setting {
-  background-color: transparent;
+  flex-grow: 1;
+  background: transparent;
 }
+
+.views-ui-views-tab-bucket-actions {
+  margin-right: 5px; /* LTR */
+}
+[dir="rtl"] .views-ui-views-tab-bucket-actions {
+  margin-right: 0;
+  margin-left: 5px;
+}
+
 .views-ui-display-tab-bucket .views-group-text {
   margin-top: 6px;
   margin-bottom: 6px;
 }
 .views-display-setting .label {
   margin-right: 3px; /* LTR */
+  font-weight: bold;
 }
 [dir="rtl"] .views-display-setting .label {
   margin-right: 0;
@@ -768,38 +666,6 @@ td.group-title {
   margin-bottom: 18px;
   line-height: 1.4555;
 }
-
-.js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  position: absolute;
-  z-index: 2;
-  top: -1px;
-  right: -5px; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  right: auto;
-  left: -5px;
-}
-
-.views-display-top .dropbutton-wrapper {
-  position: absolute;
-  top: 5px;
-  right: 4px; /* LTR */
-}
-[dir="rtl"] .views-display-top .dropbutton-wrapper {
-  right: auto;
-  left: 4px;
-}
-
-.views-ui-display-tab-bucket .dropbutton-wrapper {
-  position: absolute;
-  top: 3px;
-  right: 3px; /* LTR */
-}
-[dir="rtl"] .views-ui-display-tab-bucket .dropbutton-wrapper {
-  right: auto;
-  left: 3px;
-}
-
 .views-list-section {
   margin-bottom: 2em;
 }
diff --git a/core/themes/seven/css/components/buttons.css b/core/themes/seven/css/components/buttons.css
index c747f65274..8e46f2f850 100644
--- a/core/themes/seven/css/components/buttons.css
+++ b/core/themes/seven/css/components/buttons.css
@@ -20,6 +20,10 @@
  * @todo Consider moving box-sizing into base.css under a universal selector.
  * See https://www.drupal.org/node/2124251
  *
+ * These styles have been duplicated to dropbutton.css and splitbutton.css
+ * since those components inherits most of these design elements. Whenever
+ * making changes to this file, remember to check if that needs to be applied to
+ * dropbutton.css or splitbutton.css as well.
  */
 .button {
   position: relative;  /* 1 */
diff --git a/core/themes/seven/css/components/splitbutton.css b/core/themes/seven/css/components/splitbutton.css
new file mode 100644
index 0000000000..1638c29afb
--- /dev/null
+++ b/core/themes/seven/css/components/splitbutton.css
@@ -0,0 +1,170 @@
+/**
+ * @file
+ * Splitbuttons.
+ */
+
+.splitbutton {
+  font-size: 14px;
+  font-size: 0.875rem;
+  line-height: normal;
+}
+
+.splitbutton--small,
+.splitbutton--extrasmall {
+  font-size: 10px;
+  font-size: 0.625rem;
+}
+
+.splitbutton__action--main.splitbutton__action--main,
+.splitbutton__toggle.splitbutton__toggle {
+  margin: 0;
+  border-radius: 0;
+}
+
+.splitbutton__action--main.splitbutton__action--main:first-child,
+.splitbutton__toggle.splitbutton__toggle:first-child {
+  border-radius: 20em 0 0 20em; /* LTR */
+}
+
+.splitbutton__action--main.splitbutton__action--main:last-child,
+.splitbutton__toggle.splitbutton__toggle:last-child {
+  border-top-right-radius: 20em;
+  border-bottom-right-radius: 20em;
+}
+
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle:first-child {
+  border-radius: 0 20em 20em 0;
+}
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle:last-child {
+  border-radius: 20em 0 0 20em;
+}
+[dir="rtl"] .splitbutton__action--main.splitbutton__action--main:first-child:last-child,
+[dir="rtl"] .splitbutton__toggle.splitbutton__toggle:first-child:last-child {
+  border-radius: 20em;
+}
+
+.splitbutton__toggle--no-label {
+  min-width: 2em;
+  padding: 0.1em 0.5em;
+  font-size: inherit;
+}
+
+.splitbutton__toggle--no-label .splitbutton__toggle-arrow {
+  margin-left: -0.16em; /* LTR */
+}
+[dir="rtl"] .splitbutton__toggle--no-label .splitbutton__toggle-arrow {
+  margin-right: -0.16em;
+  margin-left: 0;
+}
+
+.splitbutton--small .splitbutton__toggle--no-label,
+.splitbutton--extrasmall .splitbutton__toggle--no-label {
+  font-size: 1.3em;
+}
+
+/**
+ * Styles for the main splitbutton items.
+ * Duplicates base button styles.
+ */
+.splitbutton__action--main {
+  position: relative;
+  display: inline-block;
+  box-sizing: border-box;
+  padding: 4px 1.5em;
+  cursor: pointer;
+  -webkit-transition: all 0.1s;
+  transition: all 0.1s;
+  text-align: left; /* LTR; This is 'center' at the base button styles. */
+  text-decoration: none;
+  color: #333;
+  border: 1px solid #a6a6a6;
+  background-color: #f2f1eb;
+  background-image: -webkit-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image: linear-gradient(to bottom, #f6f6f3, #e7e7df);
+  text-shadow: 0 1px hsla(0, 0%, 100%, 0.6);
+  font-size: inherit;
+  font-weight: 600;
+  line-height: inherit;
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  -webkit-font-smoothing: antialiased;
+}
+[dir="rtl"] .splitbutton__action--main {
+  text-align: right;
+}
+
+.splitbutton__action--main:hover,
+.splitbutton__action--main:focus {
+  text-decoration: none;
+  color: #1a1a1a;
+  outline: none;
+  background-color: #f9f8f6;
+  background-image: -webkit-linear-gradient(top, #fcfcfa, #e9e9dd);
+  background-image: linear-gradient(to bottom, #fcfcfa, #e9e9dd);
+}
+.splitbutton__action--main:hover {
+  box-shadow: 0 1px 2px hsla(0, 0%, 0%, 0.125);
+}
+
+/* Prevent focus ring being covered by next siblings. */
+.splitbutton__action--main:focus {
+  z-index: 10;
+  border: 1px solid #3ab2ff;
+  box-shadow: 0 0 0.5em 0.1em hsla(203, 100%, 60%, 0.7);
+}
+.splitbutton__action--main:active {
+  -webkit-transition: none;
+  transition: none;
+  border: 1px solid #a6a6a6;
+  background-color: #dfdfd9;
+  background-image: -webkit-linear-gradient(top, #f6f6f3, #e7e7df);
+  background-image: linear-gradient(to bottom, #f6f6f3, #e7e7df);
+  box-shadow: inset 0 1px 3px hsla(0, 0%, 0%, 0.2);
+}
+
+.splitbutton__list {
+  padding-top: 0.4em;
+  padding-bottom: 0.4em;
+  border-radius: 0.4em;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary {
+  margin: 0;
+  padding: 0.33em 1em;
+  text-align: left; /* LTR */
+  text-decoration: none;
+  color: #000;
+  border: 0;
+  border-radius: 0;
+  background: #fff;
+  box-shadow: 0;
+  text-shadow: none;
+  font: inherit;
+  -webkit-font-smoothing: inherit;
+}
+[dir="rtl"] .splitbutton__action--secondary.splitbutton__action--secondary {
+  text-align: right;
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: 0.5em 1em;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:hover {
+  text-decoration: none;
+  color: #000;
+  background: #c7eaff;
+  box-shadow: none;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:focus {
+  text-decoration: underline;
+  outline: inherit;
+}
+
+.splitbutton__action--secondary.splitbutton__action--secondary:focus:hover {
+  text-decoration: none;
+}
diff --git a/core/themes/seven/css/components/views-ui.css b/core/themes/seven/css/components/views-ui.css
index bb79f4d161..50c6036ac9 100644
--- a/core/themes/seven/css/components/views-ui.css
+++ b/core/themes/seven/css/components/views-ui.css
@@ -95,6 +95,10 @@ details.fieldset-no-legend {
 
 /* @group Lists */
 
+.views-ui-views-display-add-actions.splitbutton.splitbutton.splitbutton.splitbutton .splitbutton__toggle {
+  border-radius: 7px;
+}
+
 .views-admin ul.secondary,
 .views-admin .item-list ul {
   margin: 0;
@@ -103,7 +107,8 @@ details.fieldset-no-legend {
 
 .views-displays ul.secondary li a,
 .views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
+.views-displays ul.secondary li.is-active a.is-active,
+.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle {
   padding: 2px 7px 3px;
 }
 
@@ -111,23 +116,28 @@ details.fieldset-no-legend {
   color: #0074bd;
 }
 
-.views-displays ul.secondary li.is-active a,
-.views-displays ul.secondary li.is-active a.is-active {
-  border: 1px solid transparent;
+.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle {
+  color: #0074bd;
+  background: #fff;
+  box-shadow: none;
+  text-shadow: none;
+  font: inherit;
+  font-size: small;
+  line-height: 1.3333;
+  -webkit-font-smoothing: inherit;
 }
-
-.views-admin .links li {
-  padding-right: 0; /* LTR */
+.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:focus .splitbutton__toggle-label {
+  text-decoration: underline;
 }
-[dir="rtl"] .views-admin .links li {
-  padding-left: 0;
+.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:hover {
+  color: #fff;
+  background: #555;
+  box-shadow: none;
 }
 
-.views-admin .button .links li {
-  padding-right: 12px; /* LTR */
-}
-[dir="rtl"] .views-admin .button .links li {
-  padding-left: 12px;
+.views-displays ul.secondary li.is-active a,
+.views-displays ul.secondary li.is-active a.is-active {
+  border: 1px solid transparent;
 }
 
 .views-display-top ul.secondary {
@@ -138,11 +148,6 @@ details.fieldset-no-legend {
   float: right;
 }
 
-.views-display-top .secondary .action-list li {
-  float: none;
-  margin: 0;
-}
-
 /* @end */
 
 /* @group Tables */
@@ -178,35 +183,6 @@ details.fieldset-no-legend {
   background-position: center 3px;
 }
 
-.views-displays .secondary a:hover > .icon.add {
-  background-position: center -25px;
-}
-
-.views-displays .secondary .open > a {
-  border-radius: 7px 7px 0 0;
-}
-
-.views-displays .secondary .open > a:hover,
-.views-displays .secondary .open > a:focus {
-  color: #008bcb;
-  background-color: #f1f1f1;
-}
-
-.views-displays .secondary .action-list li:first-child {
-  border-radius: 0 7px 0 0; /* LTR */
-}
-[dir="rtl"] .views-displays .secondary .action-list li:first-child {
-  border-radius: 7px 0 0 0;
-}
-
-.views-displays .secondary .action-list li:last-child {
-  border-radius: 0 0 7px 7px;
-}
-
-.views-displays .secondary .action-list input.form-submit {
-  color: #008bcb;
-}
-
 /* @end */
 
 /* @group Attachment buckets
@@ -214,7 +190,7 @@ details.fieldset-no-legend {
  * These are the individual "buckets," or boxes, inside the display settings area
  */
 
-.views-ui-display-tab-bucket h3 {
+.views-ui-display-tab-bucket .views-ui-display-tab-bucket__title {
   text-transform: uppercase;
 }
 
diff --git a/core/themes/seven/seven.info.yml b/core/themes/seven/seven.info.yml
index 5f5763d03f..6d75045ac3 100644
--- a/core/themes/seven/seven.info.yml
+++ b/core/themes/seven/seven.info.yml
@@ -64,6 +64,9 @@ libraries-extend:
     - seven/media_library
   tour/tour-styling:
     - seven/tour-styling
+  core/drupal.splitbutton:
+    - seven/drupal.splitbutton
+
 quickedit_stylesheets:
   - css/components/quickedit.css
 regions:
diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml
index c08424f648..484872c004 100644
--- a/core/themes/seven/seven.libraries.yml
+++ b/core/themes/seven/seven.libraries.yml
@@ -143,3 +143,9 @@ layout_builder_content_translation_admin:
   css:
     component:
       css/components/layout-builder-content-translation.css: {}
+
+drupal.splitbutton:
+  version: VERSION
+  css:
+    component:
+      css/components/splitbutton.css: {}
diff --git a/core/themes/stable/css/core/splitbutton/splitbutton.css b/core/themes/stable/css/core/splitbutton/splitbutton.css
new file mode 100644
index 0000000000..1b134ae21e
--- /dev/null
+++ b/core/themes/stable/css/core/splitbutton/splitbutton.css
@@ -0,0 +1,160 @@
+/**
+ * @file
+ * Base styles for splitbuttons.
+ */
+
+.splitbutton {
+  position: relative;
+  display: inline-block;
+  max-width: 245px;
+}
+
+.splitbutton--small,
+.splitbutton--extrasmall {
+  font-size: 10px;
+  line-height: normal;
+}
+
+.splitbutton__action,
+.splitbutton__toggle {
+  position: relative;
+  display: inline-block;
+  box-sizing: border-box;
+  padding: 0.25em 0.75em;
+  text-align: left; /* LTR */
+  text-decoration: none;
+  color: #000;
+  border: 0;
+  background: #fff;
+  font-size: inherit;
+  line-height: inherit;
+}
+[dir="rtl"] .splitbutton__action,
+[dir="rtl"] .splitbutton__toggle {
+  text-align: right;
+}
+
+.splitbutton__main-items {
+  display: inline-flex;
+}
+
+.splitbutton__action--main,
+.splitbutton__toggle {
+  border: 1px solid #bbb;
+}
+
+.splitbutton__action.field-add-more-submit {
+  margin-top: 0;
+}
+
+.splitbutton__action--main:first-child,
+.splitbutton__toggle:first-child {
+  margin-right: 0; /* LTR */
+  border-top-left-radius: 2em; /* LTR */
+  border-bottom-left-radius: 2em; /* LTR */
+}
+[dir="rtl"] .splitbutton__action--main:first-child,
+[dir="rtl"] .splitbutton__toggle:first-child {
+  margin-left: 0;
+  border-radius: 0 2em 2em 0;
+}
+
+.splitbutton__action--main:first-child + .splitbutton__action--main,
+.splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-left: -1px;
+}
+
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__action--main,
+[dir="rtl"] .splitbutton__action--main:first-child + .splitbutton__toggle {
+  margin-right: -1px;
+  margin-left: 0;
+}
+
+.splitbutton__action--main:last-child,
+.splitbutton__toggle:last-child {
+  margin-right: 0; /* LTR */
+  border-top-right-radius: 2em; /* LTR */
+  border-bottom-right-radius: 2em; /* LTR */
+}
+[dir="rtl"] .splitbutton__action--main:last-child,
+[dir="rtl"] .splitbutton__toggle:last-child {
+  margin-left: 0;
+  border-radius: 2em 0 0 2em;
+}
+
+/**
+ * Since :first-child:last-child is stronger than :only-child, we don't have to
+ * provide [dir="rtl"] selectors.
+ **/
+.splitbutton__action--main:first-child:last-child,
+.splitbutton__toggle:first-child:last-child {
+  border-radius: 2em;
+}
+
+.splitbutton__toggle {
+  cursor: pointer;
+  white-space: nowrap;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+.splitbutton__toggle--no-label,
+[dir="rtl"] .splitbutton__toggle--no-label {
+  text-align: center;
+}
+
+.splitbutton__toggle-arrow {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  transform: translate(0, -50%);
+  border-width: 0.3333em 0.3333em 0;
+  border-style: solid;
+  border-right-color: transparent;
+  border-left-color: transparent;
+  line-height: 0;
+}
+.splitbutton.open .splitbutton__toggle-arrow {
+  border-top: 0;
+  border-bottom: 0.3333em solid;
+}
+
+.splitbutton__list {
+  z-index: 501;
+  box-sizing: border-box;
+  min-width: 100%;
+  max-width: 245px;
+  margin: 0.25em 0; /* LTR */
+  padding: 0.25em 0;
+  list-style: none;
+  color: #000;
+  border: 1px solid #aaa;
+  border-radius: 0.25em;
+  background: #fff;
+}
+[dir="rtl"] .splitbutton__list {
+  margin: 0.25em 0;
+}
+
+.splitbutton__action--secondary {
+  min-width: 100%;
+  white-space: normal;
+}
+
+.splitbutton--small .splitbutton__action--secondary,
+.splitbutton--extrasmall .splitbutton__action--secondary {
+  padding: 0.5em 0.75em;
+}
+
+.js .splitbutton__list:not(.open) {
+  display: none;
+}
+
+.splitbutton__action:focus {
+  z-index: 1;
+}
+
+.splitbutton__action--secondary:hover {
+  color: #000;
+  background: #c7eaff;
+}
diff --git a/core/themes/stable/css/views_ui/views_ui.admin.css b/core/themes/stable/css/views_ui/views_ui.admin.css
index 2507d30657..de79c5a65c 100644
--- a/core/themes/stable/css/views_ui/views_ui.admin.css
+++ b/core/themes/stable/css/views_ui/views_ui.admin.css
@@ -4,7 +4,6 @@
  * declarations. For example: display, position, float, clear, and overflow.
  */
 
-.views-admin ul,
 .views-admin menu,
 .views-admin dir {
   padding: 0;
@@ -100,10 +99,6 @@
   border-right: 1px solid #bfbfbf;
   border-left: 0 none;
 }
-.views-displays .tabs .open > a {
-  position: relative;
-  z-index: 51;
-}
 .views-displays .tabs .views-display-deleted-link {
   text-decoration: line-through;
 }
@@ -120,23 +115,6 @@
 .views-display-tab .details-wrapper > .views-ui-display-tab-bucket .actions {
   opacity: 1;
 }
-.views-displays .tabs .add {
-  position: relative;
-}
-.views-displays .tabs .action-list {
-  position: absolute;
-  z-index: 50;
-  top: 23px;
-  left: 0; /* LTR */
-  margin: 0;
-}
-[dir="rtl"] .views-displays .tabs .action-list {
-  right: 0;
-  left: auto;
-}
-.views-displays .tabs .action-list li {
-  display: block;
-}
 .views-display-columns .details-wrapper {
   padding: 0;
 }
@@ -203,6 +181,3 @@ html.js .js-only {
 html.js span.js-only {
   display: inline;
 }
-.js .views-edit-view .dropbutton-wrapper {
-  width: auto;
-}
diff --git a/core/themes/stable/css/views_ui/views_ui.admin.theme.css b/core/themes/stable/css/views_ui/views_ui.admin.theme.css
index 32de3f97c5..e5a55d330c 100644
--- a/core/themes/stable/css/views_ui/views_ui.admin.theme.css
+++ b/core/themes/stable/css/views_ui/views_ui.admin.theme.css
@@ -104,9 +104,6 @@
 .views-displays .tabs a:hover > .icon.add {
   background-position: center -25px;
 }
-.views-displays .tabs .open a:hover > .icon.add {
-  background-position: center 3px;
-}
 details.box-padding {
   border: none;
 }
@@ -295,33 +292,37 @@ td.group-title {
 }
 .views-display-top {
   position: relative;
-  padding: 8px 8px 3px;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  padding: 6px 8px;
   border-bottom: 1px solid #ccc;
   background-color: #e1e2dc;
 }
-.views-display-top .tabs {
-  margin-right: 18em; /* LTR */
-}
-[dir="rtl"] .views-display-top .tabs {
-  margin-right: 0;
-  margin-left: 18em;
-}
-.views-display-top .tabs > li {
-  margin-right: 6px; /* LTR */
+.views-display-top .tabs.secondary > li {
+  margin: 2px 5px 2px 6px; /* LTR */
   padding-left: 0; /* LTR */
 }
-[dir="rtl"] .views-display-top .tabs > li {
-  margin-right: 0.3em;
-  margin-left: 6px;
+[dir="rtl"] .views-display-top .tabs.secondary > li {
+  margin-right: 6px;
+  margin-left: 5px;
   padding-right: 0;
 }
-.views-display-top .tabs > li:last-child {
+.views-display-top .tabs.secondary > li:last-child {
   margin-right: 0; /* LTR */
 }
-[dir="rtl"] .views-display-top .tabs > li:last-child {
+[dir="rtl"] .views-display-top .tabs.secondary > li:last-child {
   margin-right: 0.3em;
   margin-left: 0;
 }
+.views-ui-views-extra-actions {
+  margin: 2px 5px 2px 6px;
+}
+[dir="rtl"] .views-ui-views-extra-actions {
+  margin-right: 6px;
+  margin-left: 5px;
+}
+
 .form-edit .form-actions {
   margin-top: 0;
   padding: 8px 12px;
@@ -331,12 +332,8 @@ td.group-title {
   background-color: #e1e2dc;
 }
 .views-displays .tabs.secondary {
-  margin-right: 200px; /* LTR */
-  border: 0;
-}
-[dir="rtl"] .views-displays .tabs.secondary {
-  margin-right: 0;
-  margin-left: 200px;
+  flex-grow: 1;
+  list-style: none;
 }
 .views-displays .tabs.secondary li,
 .views-displays .tabs.secondary li.is-active {
@@ -345,16 +342,6 @@ td.group-title {
   border: 0;
   background: transparent;
 }
-.views-displays .tabs li.add ul.action-list li {
-  margin: 0;
-}
-.views-displays .tabs.secondary li {
-  margin: 0 5px 5px 6px; /* LTR */
-}
-[dir="rtl"] .views-displays .tabs.secondary li {
-  margin-right: 6px;
-  margin-left: 5px;
-}
 .views-displays .tabs.secondary .tabs__tab + .tabs__tab {
   border-top: 0;
 }
@@ -365,11 +352,13 @@ td.group-title {
 [dir="rtl"] .views-displays .tabs li.tabs__tab:hover {
   padding-right: 0;
 }
-.views-displays .tabs.secondary a {
+.views-displays .tabs.secondary a,
+.views-ui-views-display-add-actions .splitbutton__toggle.splitbutton__toggle {
   display: inline-block;
   padding: 3px 7px;
   border: 1px solid #cbcbcb;
   border-radius: 7px;
+  font-family: inherit;
   font-size: small;
   line-height: 1.3333;
 }
@@ -387,60 +376,23 @@ td.group-title {
 .views-displays .tabs.secondary li a {
   background-color: #fff;
 }
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:focus {
+  text-decoration: underline;
+}
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:hover {
+  color: #000;
+  background: #fff;
+}
 .views-displays .tabs li a:hover,
 .views-displays .tabs li.is-active a,
-.views-displays .tabs li.is-active a.is-active {
+.views-displays .tabs li.is-active a.is-active,
+.splitbutton.views-ui-views-display-add-actions.splitbutton .splitbutton__toggle:hover {
   color: #fff;
   background-color: #555;
 }
-.views-displays .tabs .open > a {
-  position: relative;
-  border-bottom: 1px solid transparent;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .open > a:hover {
-  color: #0074bd;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li {
-  padding: 2px 9px;
-  border-width: 0 1px;
-  border-style: solid;
-  border-color: #cbcbcb;
-  background-color: #f1f1f1;
-}
-.views-displays .tabs .action-list li:first-child {
-  border-width: 1px 1px 0;
-}
-.views-displays .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list li:last-child {
-  border-width: 0 1px 1px;
-}
-.views-displays .tabs .action-list input.form-submit {
-  margin: 0;
-  padding: 0;
-  border: medium none;
-  background: none repeat scroll 0 0 transparent;
-}
-.views-displays .tabs .action-list input.form-submit:hover {
-  box-shadow: none;
-}
-.views-displays .tabs .action-list li:hover {
-  background-color: #ddd;
-}
 .edit-display-settings {
   margin: 12px 12px 0 12px;
 }
-.edit-display-settings-top.views-ui-display-tab-bucket {
-  position: relative;
-  margin: 0 0 15px 0;
-  padding-top: 4px;
-  padding-bottom: 4px;
-  border: 1px solid #f3f3f3;
-  line-height: 20px;
-}
 .views-display-column {
   border: 1px solid #f3f3f3;
 }
@@ -504,11 +456,36 @@ td.group-title {
 .views-ui-display-tab-bucket + .views-ui-display-tab-bucket {
   border-top: medium none;
 }
-.views-ui-display-tab-bucket__title,
+
+.views-ui-display-tab-actions.views-ui-display-tab-bucket {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin-bottom: 15px;
+  padding-bottom: 4px;
+  border: 1px solid #f3f3f3;
+  line-height: 20px;
+}
+.views-ui-views-tab-bucket-actions {
+  margin-right: 5px; /* LTR */
+}
+[dir="rtl"] .views-ui-views-tab-bucket-actions {
+  margin-right: 0;
+  margin-left: 5px;
+}
+
+.views-ui-display-tab-bucket__header {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+}
+
+.views-ui-display-tab-bucket__header,
 .views-ui-display-tab-bucket > .views-display-setting {
   padding: 2px 6px 4px;
 }
 .views-ui-display-tab-bucket__title {
+  flex-grow: 1;
   margin: 0;
   font-size: small;
 }
@@ -551,7 +528,8 @@ td.group-title {
 .views-ui-display-tab-bucket .views-display-setting:nth-of-type(even) {
   background-color: #f3f5ee;
 }
-.views-ui-display-tab-actions.views-ui-display-tab-bucket .views-display-setting {
+.views-ui-display-tab-actions .views-display-setting {
+  flex-grow: 1;
   background-color: transparent;
 }
 .views-ui-display-tab-bucket .views-group-text {
@@ -767,80 +745,6 @@ td.group-title {
   margin-bottom: 18px;
   line-height: 1.4555;
 }
-.dropbutton-multiple {
-  position: absolute;
-}
-.dropbutton-widget {
-  position: relative;
-}
-.js .views-edit-view .dropbutton-wrapper .dropbutton .dropbutton-action > * {
-  font-size: 10px;
-}
-.js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  position: absolute;
-  z-index: 2;
-  top: -1px;
-  right: -5px; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper .dropbutton .dropbutton-action > .ajax-progress-throbber {
-  right: auto;
-  left: -5px;
-}
-.js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:first-child a {
-  border-radius: 1.1em 0 0 0; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:first-child a {
-  border-radius: 0 1.1em 0 0;
-}
-.js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:last-child a {
-  border-radius: 0 0 0 1.1em; /* LTR */
-}
-[dir="rtl"].js .dropbutton-wrapper.dropbutton-multiple.open .dropbutton-action:last-child a {
-  border-radius: 0 0 1.1em 0;
-}
-.views-display-top .dropbutton-wrapper {
-  position: absolute;
-  top: 7px;
-  right: 12px; /* LTR */
-}
-[dir="rtl"] .views-display-top .dropbutton-wrapper {
-  right: auto;
-  left: 12px;
-}
-.views-display-top .dropbutton-wrapper .dropbutton-widget .dropbutton-action a {
-  width: auto;
-}
-
-.views-ui-display-tab-bucket .dropbutton-wrapper {
-  position: absolute;
-  top: 4px;
-  right: 5px; /* LTR */
-}
-[dir="rtl"] .views-ui-display-tab-bucket .dropbutton-wrapper {
-  right: auto;
-  left: 5px;
-}
-.views-ui-display-tab-bucket .dropbutton-wrapper .dropbutton-widget .dropbutton-action a {
-  width: auto;
-}
-.views-ui-display-tab-actions .dropbutton-wrapper li a,
-.views-ui-display-tab-actions .dropbutton-wrapper input {
-  margin-bottom: 0;
-  padding-left: 12px; /* LTR */
-  border: medium;
-  background: none;
-  font-family: inherit;
-  font-size: 12px;
-}
-[dir="rtl"] .views-ui-display-tab-actions .dropbutton-wrapper li a,
-[dir="rtl"] .views-ui-display-tab-actions .dropbutton-wrapper input {
-  padding-right: 12px;
-  padding-left: 0.5em;
-}
-.views-ui-display-tab-actions .dropbutton-wrapper input:hover {
-  border: none;
-  background: none;
-}
 .views-list-section {
   margin-bottom: 2em;
 }
diff --git a/core/themes/stable/stable.info.yml b/core/themes/stable/stable.info.yml
index 0f20f7c604..608db4af6e 100644
--- a/core/themes/stable/stable.info.yml
+++ b/core/themes/stable/stable.info.yml
@@ -85,6 +85,13 @@ libraries-override:
     css:
       component:
         misc/dropbutton/dropbutton.css: css/core/dropbutton/dropbutton.css
+
+  core/drupal.splitbutton:
+    css:
+      component:
+        misc/splitbutton/splitbutton.css: css/core/splitbutton/splitbutton.css
+
+
   core/drupal.vertical-tabs:
     css:
       component:
diff --git a/core/themes/stable/templates/admin/views-ui-display-tab-bucket.html.twig b/core/themes/stable/templates/admin/views-ui-display-tab-bucket.html.twig
index 32dbdd7e24..0a2661e2f7 100644
--- a/core/themes/stable/templates/admin/views-ui-display-tab-bucket.html.twig
+++ b/core/themes/stable/templates/admin/views-ui-display-tab-bucket.html.twig
@@ -23,11 +23,13 @@
   ]
 %}
 <div{{ attributes.addClass(classes) }}>
-  {% if title -%}
+  <div class="views-ui-display-tab-bucket__header">
+    {% if title -%}
     <h3 class="views-ui-display-tab-bucket__title">{{ title }}</h3>
-  {%- endif %}
-  {% if actions -%}
+    {%- endif %}
+    {% if actions -%}
     {{ actions }}
-  {%- endif %}
+    {%- endif %}
+  </div>
   {{ content }}
 </div>
diff --git a/core/themes/stable/templates/form/splitbutton.html.twig b/core/themes/stable/templates/form/splitbutton.html.twig
new file mode 100644
index 0000000000..0811b6d727
--- /dev/null
+++ b/core/themes/stable/templates/form/splitbutton.html.twig
@@ -0,0 +1,65 @@
+{#
+/**
+ * @file
+ * Default theme implementation of a splitbutton used to wrap child elements.
+ *
+ * Used for grouped buttons and link items.
+ *
+ * Available variables:
+ * - attributes: HTML attributes for the containing element.
+ * - content_attributes: HTML attributes for the list element.
+ * - item_attributes: HTML attributes for the list item.
+ * - main_items: The uncollapsed splitbutton elements.
+ * - items: Further child elements of the splitbutton.
+ * - multiple: Whether the splitbutton has subitems.
+ * - trigger_label: The label of the toggle.
+ * - trigger_label_visible: Whether the label of the toggle should be visible.
+ *
+ * @see template_preprocess_splitbutton()
+ */
+#}
+{% if main_items or items %}
+{%
+  set classes = [
+    'splitbutton',
+    multiple ? 'splitbutton--multiple' : 'splitbutton--single'
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {% if not multiple %}
+    <div class="splitbutton__main-items">
+      {% for main_item in main_items %}
+        {{ main_item.value }}
+      {% endfor %}
+    </div>
+  {% else %}
+    {%
+      set trigger_placeholder_classes = [
+        'button',
+        'splitbutton__toggle',
+        trigger_label_visible ? 'splitbutton__toggle--with-label' : 'splitbutton__toggle--no-label'
+      ]
+    %}
+    {%
+      set trigger_placeholder_attributes = create_attribute({'class': trigger_placeholder_classes})
+    %}
+    <div class="splitbutton__main-items">
+      {% for main_item in main_items %}
+        {{ main_item.value }}
+      {% endfor %}
+      <span{{ trigger_placeholder_attributes.addClass('js-splitbutton-toggle-placeholder') }}>
+        <span class="splitbutton__toggle-label{{ trigger_label_visible ? '' : ' visually-hidden' }}">{{ trigger_label }}</span>
+        <span class="splitbutton__toggle-arrow invisible"></span>
+      </span>
+    </div>
+
+    {% if items %}
+    <ul{{ content_attributes.addClass('splitbutton__list') }}>
+      {% for item in items %}
+        <li{{ item.attributes.addClass('splitbutton__list-item') }}>{{ item.value }}</li>
+      {% endfor %}
+    </ul>
+    {% endif %}
+  {% endif %}
+</div>
+{% endif %}
