diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 50abc2e501ce8d6b18cdf5f677b399a77700017a..cd99207c0fabfad526cae7a808dd5e23aaf49b72 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -575,15 +575,11 @@ drupal.displace:
 drupal.dropbutton:
   version: VERSION
   js:
-    misc/dropbutton/dropbutton.js: {}
+    # Needed to make sure the element is loaded before connectedCallback is executed.
+    misc/dropbutton/dropbutton.js: { attributes: { defer: true } }
   css:
     component:
       misc/dropbutton/dropbutton.css: {}
-  dependencies:
-    - core/jquery
-    - core/drupal
-    - core/drupalSettings
-    - core/once
 
 drupal.entity-form:
   version: VERSION
diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js
index 1f14dc12817d0eee5c4b72629919e44a99dd70a6..e2ce7bc37b51c5953bcd491a46c18e57062b0e0f 100644
--- a/core/misc/dropbutton/dropbutton.js
+++ b/core/misc/dropbutton/dropbutton.js
@@ -3,234 +3,117 @@
  * Dropbutton feature.
  */
 
-(function ($, Drupal) {
-  /**
-   * A DropButton presents an HTML list as a button with a primary action.
-   *
-   * All secondary actions beyond the first in the list are presented in a
-   * dropdown list accessible through a toggle arrow associated with the button.
-   *
-   * @constructor Drupal.DropButton
-   *
-   * @param {HTMLElement} dropbutton
-   *   A DOM element.
-   * @param {object} settings
-   *   A list of options including:
-   * @param {string} settings.title
-   *   The text inside the toggle link element. This text is hidden
-   *   from visual UAs.
-   */
-  function DropButton(dropbutton, settings) {
-    // Merge defaults with settings.
-    const options = $.extend(
-      { title: Drupal.t('List additional actions') },
-      settings,
-    );
-    const $dropbutton = $(dropbutton);
+customElements.define(
+  'drupal-dropbutton',
+  class DrupalDropbutton extends HTMLElement {
+    connectedCallback() {
+      const settings = drupalSettings?.dropbutton;
+      // Merge defaults with settings.
+      const options = {
+        title: Drupal.t('List additional actions'),
+        ...settings,
+      };
+
+      const actions = this.querySelectorAll('.dropbutton li');
+
+      // Add the special dropdown only if there are hidden actions.
+      if (actions.length > 1) {
+        // Identify the first element of the collection.
+        const primary = actions[0];
+
+        this.classList.add('dropbutton-multiple');
+        actions.forEach((li) =>
+          li.classList.add('dropbutton-action', 'secondary-action'),
+        );
+        primary.classList.remove('secondary-action');
+        // Add toggle link.
+        primary.insertAdjacentHTML(
+          'afterend',
+          DrupalDropbutton.dropbuttonToggle(options),
+        );
+
+        this.addEventListener('click', this);
+        this.addEventListener('mouseleave', this);
+        this.addEventListener('mouseenter', this);
+        this.addEventListener('focusout', this);
+        this.addEventListener('focusin', this);
+      } else {
+        this.classList.add('dropbutton-single');
+      }
+    }
+
+    disconnectedCallback() {
+      this.removeEventListener('click', this);
+      this.removeEventListener('mouseleave', this);
+      this.removeEventListener('mouseenter', this);
+      this.removeEventListener('focusout', this);
+      this.removeEventListener('focusin', this);
+    }
+
+    handleEvent(event) {
+      if (
+        event.type === 'click' &&
+        event.target.matches('[data-drupal-dropbutton-toggle]')
+      ) {
+        event.preventDefault();
+        this.toggle();
+      } else if (['mouseleave', 'focusout'].includes(event.type)) {
+        this.hoverOut();
+      } else if (['mouseenter', 'focusin'].includes(event.type)) {
+        this.hoverIn();
+      }
+    }
 
     /**
-     * @type {jQuery}
+     * Toggle the dropbutton open and closed.
+     *
+     * @param {boolean} [show]
+     *   Force the dropbutton to open by passing true or to close by
+     *   passing false.
      */
-    this.$dropbutton = $dropbutton;
+    toggle(show) {
+      const isBool = typeof show === 'boolean';
+      show = isBool ? show : !this.classList.contains('open');
+      this.classList.toggle('open', show);
+    }
 
     /**
-     * @type {jQuery}
+     * @method
      */
-    this.$list = $dropbutton.find('.dropbutton');
+    hoverIn() {
+      // Clear any previous timer we were using.
+      if (this.timerID) {
+        window.clearTimeout(this.timerID);
+      }
+    }
 
     /**
-     * Find actions and mark them.
-     *
-     * @type {jQuery}
+     * @method
      */
-    this.$actions = this.$list.find('li').addClass('dropbutton-action');
-
-    // Add the special dropdown only if there are hidden actions.
-    if (this.$actions.length > 1) {
-      // Identify the first element of the collection.
-      const $primary = this.$actions.slice(0, 1);
-      // Identify the secondary actions.
-      const $secondary = this.$actions.slice(1);
-      $secondary.addClass('secondary-action');
-      // Add toggle link.
-      $primary.after(Drupal.theme('dropbuttonToggle', options));
-      // Bind mouse events.
-      this.$dropbutton.addClass('dropbutton-multiple').on({
-        /**
-         * Adds a timeout to close the dropdown on mouseleave.
-         *
-         * @ignore
-         */
-        'mouseleave.dropbutton': this.hoverOut.bind(this),
-
-        /**
-         * Clears timeout when mouseout of the dropdown.
-         *
-         * @ignore
-         */
-        'mouseenter.dropbutton': this.hoverIn.bind(this),
-
-        /**
-         * Similar to mouseleave/mouseenter, but for keyboard navigation.
-         *
-         * @ignore
-         */
-        'focusout.dropbutton': this.focusOut.bind(this),
+    hoverOut() {
+      // Wait half a second before closing.
+      this.timerID = window.setTimeout(() => this.close(), 500);
+    }
 
-        /**
-         * @ignore
-         */
-        'focusin.dropbutton': this.focusIn.bind(this),
-      });
-    } else {
-      this.$dropbutton.addClass('dropbutton-single');
+    /**
+     * @method
+     */
+    open() {
+      this.toggle(true);
     }
-  }
 
-  /**
-   * Delegated callback for opening and closing dropbutton secondary actions.
-   *
-   * @function Drupal.DropButton~dropbuttonClickHandler
-   *
-   * @param {jQuery.Event} e
-   *   The event triggered.
-   */
-  function dropbuttonClickHandler(e) {
-    e.preventDefault();
-    $(e.target).closest('.dropbutton-wrapper').toggleClass('open');
-  }
+    /**
+     * @method
+     */
+    close() {
+      this.toggle(false);
+    }
 
-  /**
-   * Process elements with the .dropbutton class on page load.
-   *
-   * @type {Drupal~behavior}
-   *
-   * @prop {Drupal~behaviorAttach} attach
-   *   Attaches dropButton behaviors.
-   */
-  Drupal.behaviors.dropButton = {
-    attach(context, settings) {
-      const dropbuttons = once('dropbutton', '.dropbutton-wrapper', context);
-      if (dropbuttons.length) {
-        // Adds the delegated handler that will toggle dropdowns on click.
-        const body = once('dropbutton-click', 'body');
-        if (body.length) {
-          $(body).on('click', '.dropbutton-toggle', dropbuttonClickHandler);
-        }
-        // Initialize all buttons.
-        dropbuttons.forEach((dropbutton) => {
-          DropButton.dropbuttons.push(
-            new DropButton(dropbutton, settings.dropbutton),
-          );
-        });
+    static dropbuttonToggle(options) {
+      if (Drupal?.theme?.dropbuttonToggle) {
+        return Drupal.theme.dropbuttonToggle(options);
       }
-    },
-  };
-
-  /**
-   * Extend the DropButton constructor.
-   */
-  $.extend(
-    DropButton,
-    /** @lends Drupal.DropButton */ {
-      /**
-       * Store all processed DropButtons.
-       *
-       * @type {Array.<Drupal.DropButton>}
-       */
-      dropbuttons: [],
-    },
-  );
-
-  /**
-   * Extend the DropButton prototype.
-   */
-  $.extend(
-    DropButton.prototype,
-    /** @lends Drupal.DropButton# */ {
-      /**
-       * Toggle the dropbutton open and closed.
-       *
-       * @param {boolean} [show]
-       *   Force the dropbutton to open by passing true or to close by
-       *   passing false.
-       */
-      toggle(show) {
-        const isBool = typeof show === 'boolean';
-        show = isBool ? show : !this.$dropbutton.hasClass('open');
-        this.$dropbutton.toggleClass('open', show);
-      },
-
-      /**
-       * @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(this.close.bind(this), 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);
-      },
-    },
-  );
-
-  $.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.title]
-       *   The button text.
-       *
-       * @return {string}
-       *   A string representing a DOM fragment.
-       */
-      dropbuttonToggle(options) {
-        return `<li class="dropbutton-toggle"><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${options.title}</span></span></button></li>`;
-      },
-    },
-  );
-
-  // Expose constructor in the public space.
-  Drupal.DropButton = DropButton;
-})(jQuery, Drupal);
+      return `<li class="dropbutton-toggle" data-drupal-dropbutton-toggle><button type="button"><span class="dropbutton-arrow"><span class="visually-hidden">${options.title}</span></span></button></li>`;
+    }
+  },
+);
diff --git a/core/modules/system/templates/dropbutton-wrapper.html.twig b/core/modules/system/templates/dropbutton-wrapper.html.twig
index 9c87a49f6b8ea59d890c24b96d4c3063298e744f..554b88fc9d35e7ce09f75c1b5f6a6325e4d4aee3 100644
--- a/core/modules/system/templates/dropbutton-wrapper.html.twig
+++ b/core/modules/system/templates/dropbutton-wrapper.html.twig
@@ -13,10 +13,10 @@
 #}
 {% if children %}
   {% apply spaceless %}
-    <div class="dropbutton-wrapper" data-drupal-ajax-container>
+    <drupal-dropbutton class="dropbutton-wrapper" data-drupal-ajax-container>
       <div class="dropbutton-widget">
         {{ children }}
       </div>
-    </div>
+    </drupal-dropbutton>
   {% endapply %}
 {% endif %}
diff --git a/core/modules/views/tests/src/Kernel/Plugin/RowRenderCacheTest.php b/core/modules/views/tests/src/Kernel/Plugin/RowRenderCacheTest.php
index 1629bbdad047bb61a88127b8bdd90a4bc27c8c38..5990fc230d5b2a7c984cffc3643c788be49be46a 100644
--- a/core/modules/views/tests/src/Kernel/Plugin/RowRenderCacheTest.php
+++ b/core/modules/views/tests/src/Kernel/Plugin/RowRenderCacheTest.php
@@ -185,10 +185,10 @@ protected function doTestRenderedOutput(AccountInterface $account, $check_cache
       $expected = $access ? "<a href=\"$node_url/delete?destination=/\" hreflang=\"en\">delete</a>" : "";
       $output = $view->style_plugin->getField($index, 'delete_node');
       $this->assertSame($expected, (string) $output);
-      $expected = $access ? '  <div class="dropbutton-wrapper" data-drupal-ajax-container><div class="dropbutton-widget"><ul class="dropbutton">' .
+      $expected = $access ? '  <drupal-dropbutton class="dropbutton-wrapper" data-drupal-ajax-container><div class="dropbutton-widget"><ul class="dropbutton">' .
         '<li><a href="' . $node_url . '/edit?destination=/" aria-label="Edit ' . $node->label() . '" hreflang="en">Edit</a></li>' .
         '<li><a href="' . $node_url . '/delete?destination=/" aria-label="Delete ' . $node->label() . '" class="use-ajax" data-dialog-type="modal" data-dialog-options="' . Html::escape(Json::encode(['width' => 880])) . '" hreflang="en">Delete</a></li>' .
-        '</ul></div></div>' : '';
+        '</ul></div></drupal-dropbutton>' : '';
       $output = $view->style_plugin->getField($index, 'operations');
       $this->assertSame($expected, (string) $output);
 
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
index 0372ae1cd996e606dc80886bd4a64383bec57945..665afbb457b1fb80fed41bee4e64143c7d59c70f 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Ajax/ThrobberTest.php
@@ -95,7 +95,7 @@ public function testThemingThrobberElement(): void {
     $this->assertNotEmpty($web_assert->waitForElementVisible('css', '#drupal-modal'));
     hold_test_response(TRUE);
     $this->clickLink('Place block');
-    $this->assertNotNull($web_assert->waitForElement('xpath', '//div[contains(@class, "dropbutton-wrapper")]/following-sibling::div[contains(@class, "ajax-progress-throbber")]'));
+    $this->assertNotNull($web_assert->waitForElement('xpath', '//drupal-dropbutton[contains(@class, "dropbutton-wrapper")]/following-sibling::div[contains(@class, "ajax-progress-throbber")]'));
     hold_test_response(FALSE);
     $web_assert->assertNoElementAfterWait('css', '.ajax-progress-throbber');
   }
diff --git a/core/themes/claro/js/dropbutton.js b/core/themes/claro/js/dropbutton.js
index 7fb87d60c25c89067993df6e5068c83ab4258c97..106e1b58c2160162a1c24ca0a5c3b891b387d7a9 100644
--- a/core/themes/claro/js/dropbutton.js
+++ b/core/themes/claro/js/dropbutton.js
@@ -19,5 +19,5 @@
    *   A string representing a DOM fragment.
    */
   Drupal.theme.dropbuttonToggle = (options) =>
-    `<li class="dropbutton-toggle"><button type="button" class="dropbutton__toggle"><span class="visually-hidden">${options.title}</span></button></li>`;
+    `<li class="dropbutton-toggle"><button type="button" data-drupal-dropbutton-toggle class="dropbutton__toggle"><span class="visually-hidden">${options.title}</span></button></li>`;
 })(Drupal);