From 8d1ff2064739ce0428514c40461262827121e105 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Sat, 30 Mar 2024 17:23:10 +0000
Subject: [PATCH] Issue #3431452 by godotislate, smustgrave, alexpott: Rename
 RenderElement and FormElement plugin abstract classes to RenderElementBase
 and FormElementBase

---
 core/.phpstan-baseline.php                    |   2 +-
 core/core.api.php                             |   2 +-
 core/includes/form.inc                        |   8 +-
 .../Core/Datetime/Element/DateElementBase.php |   4 +-
 .../Core/Form/FormAjaxResponseBuilder.php     |   2 +-
 core/lib/Drupal/Core/Form/FormBuilder.php     |   4 +-
 core/lib/Drupal/Core/Form/FormState.php       |   4 +-
 .../Core/Plugin/PluginFormInterface.php       |   2 +-
 .../Core/Render/Annotation/FormElement.php    |   2 +-
 .../Core/Render/Annotation/RenderElement.php  |   2 +-
 .../Core/Render/Attribute/FormElement.php     |   2 +-
 .../Core/Render/Attribute/RenderElement.php   |   2 +-
 core/lib/Drupal/Core/Render/Element/Ajax.php  |   1 -
 .../lib/Drupal/Core/Render/Element/Button.php |   1 -
 .../Drupal/Core/Render/Element/Checkbox.php   |   1 -
 .../Drupal/Core/Render/Element/Checkboxes.php |   1 -
 core/lib/Drupal/Core/Render/Element/Color.php |   1 -
 .../Core/Render/Element/ComponentElement.php  |   1 -
 .../Drupal/Core/Render/Element/Container.php  |   1 -
 core/lib/Drupal/Core/Render/Element/Date.php  |   1 -
 .../Drupal/Core/Render/Element/Details.php    |   1 -
 .../Drupal/Core/Render/Element/Dropbutton.php |   1 -
 .../Core/Render/Element/ElementInterface.php  |   2 +-
 core/lib/Drupal/Core/Render/Element/Email.php |   1 -
 .../Drupal/Core/Render/Element/Fieldset.php   |   1 -
 core/lib/Drupal/Core/Render/Element/File.php  |   1 -
 core/lib/Drupal/Core/Render/Element/Form.php  |   1 -
 .../Core/Render/Element/FormElement.php       | 249 +++------
 .../Core/Render/Element/FormElementBase.php   | 223 ++++++++
 .../Render/Element/FormElementInterface.php   |   2 +-
 .../lib/Drupal/Core/Render/Element/Hidden.php |   1 -
 core/lib/Drupal/Core/Render/Element/Html.php  |   1 -
 .../Drupal/Core/Render/Element/HtmlTag.php    |   1 -
 .../Core/Render/Element/InlineTemplate.php    |   1 -
 core/lib/Drupal/Core/Render/Element/Item.php  |   1 -
 core/lib/Drupal/Core/Render/Element/Label.php |   1 -
 .../Core/Render/Element/LanguageSelect.php    |   1 -
 core/lib/Drupal/Core/Render/Element/Link.php  |   1 -
 .../lib/Drupal/Core/Render/Element/Number.php |   1 -
 core/lib/Drupal/Core/Render/Element/Page.php  |   1 -
 .../Drupal/Core/Render/Element/PageTitle.php  |   1 -
 core/lib/Drupal/Core/Render/Element/Pager.php |   1 -
 .../Drupal/Core/Render/Element/Password.php   |   1 -
 .../Core/Render/Element/PasswordConfirm.php   |   1 -
 core/lib/Drupal/Core/Render/Element/Radio.php |   1 -
 .../lib/Drupal/Core/Render/Element/Radios.php |   1 -
 .../Core/Render/Element/RenderElement.php     | 464 +----------------
 .../Core/Render/Element/RenderElementBase.php | 477 ++++++++++++++++++
 .../lib/Drupal/Core/Render/Element/Search.php |   1 -
 .../lib/Drupal/Core/Render/Element/Select.php |   1 -
 .../Core/Render/Element/StatusMessages.php    |   1 -
 .../Core/Render/Element/StatusReport.php      |   1 -
 core/lib/Drupal/Core/Render/Element/Table.php |   3 +-
 core/lib/Drupal/Core/Render/Element/Tel.php   |   1 -
 .../Drupal/Core/Render/Element/Textarea.php   |   1 -
 .../Drupal/Core/Render/Element/Textfield.php  |   1 -
 core/lib/Drupal/Core/Render/Element/Url.php   |   1 -
 core/lib/Drupal/Core/Render/Element/Value.php |   1 -
 .../Core/Render/Element/VerticalTabs.php      |   1 -
 .../lib/Drupal/Core/Render/Element/Weight.php |   1 -
 .../Drupal/Core/Render/ElementInfoManager.php |   4 +-
 core/lib/Drupal/Core/Render/theme.api.php     |  12 +-
 .../Core/TempStore/Element/BreakLockLink.php  |   2 +-
 .../src/Element/ContextualLinks.php           |   2 +-
 .../Element/ContextualLinksPlaceholder.php    |   2 +-
 .../field_layout/src/FieldLayoutBuilder.php   |   4 +-
 .../tests/src/Unit/FieldLayoutBuilderTest.php |   8 +-
 core/modules/file/src/Element/ManagedFile.php |   2 +-
 .../filter/src/Element/ProcessedText.php      |   2 +-
 .../modules/filter/src/Element/TextFormat.php |   2 +-
 core/modules/language/language.module         |   2 +-
 .../src/Element/LanguageConfiguration.php     |   2 +-
 .../src/Element/LayoutBuilder.php             |   2 +-
 core/modules/media/media.module               |   4 +-
 .../Plugin/Field/FieldType/ListItemBase.php   |   2 +-
 .../src/Element/ResponsiveImage.php           |   2 +-
 .../system/src/Element/StatusReportPage.php   |   2 +-
 .../system/templates/container.html.twig      |   4 +-
 .../src/Element/Deprecated.php                |   2 +-
 .../Element/DeprecatedExtendsFormElement.php  |  23 +
 .../DeprecatedExtendsRenderElement.php        |  23 +
 core/modules/toolbar/src/Element/Toolbar.php  |   2 +-
 .../toolbar/src/Element/ToolbarItem.php       |   2 +-
 core/modules/views/src/Element/View.php       |   2 +-
 .../Render/Element/DeprecatedElementTest.php  |  98 +++-
 .../Core/Render/Element/RenderElementTest.php |   8 +-
 .../templates/form/container.html.twig        |   4 +-
 .../templates/form/container.html.twig        |   4 +-
 88 files changed, 993 insertions(+), 732 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Render/Element/FormElementBase.php
 create mode 100644 core/lib/Drupal/Core/Render/Element/RenderElementBase.php
 create mode 100644 core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsFormElement.php
 create mode 100644 core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsRenderElement.php

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index cd78b0334c9a..789b1e63b598 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -489,7 +489,7 @@
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$sort in isset\\(\\) always exists and is not nullable\\.$#',
 	'count' => 1,
-	'path' => __DIR__ . '/lib/Drupal/Core/Render/Element/RenderElement.php',
+	'path' => __DIR__ . '/lib/Drupal/Core/Render/Element/RenderElementBase.php',
 ];
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$output in empty\\(\\) always exists and is not falsy\\.$#',
diff --git a/core/core.api.php b/core/core.api.php
index a202b580d014..4b64616e7201 100644
--- a/core/core.api.php
+++ b/core/core.api.php
@@ -2465,7 +2465,7 @@ function hook_validation_constraint_alter(array &$definitions) {
  * @section sec_query Query parameters in Ajax requests
  * If a form uses an Ajax field, all the query parameters in the current request
  * will be also added to the Ajax POST requests along with an additional
- * 'ajax_form=1' parameter (See \Drupal\Core\Render\Element\RenderElement).
+ * 'ajax_form=1' parameter (See \Drupal\Core\Render\Element\RenderElementBase).
  * @code
  * $settings['options']['query'] += \Drupal::request()->query->all();
  * $settings['options']['query'][FormBuilderInterface::AJAX_FORM_REQUEST] = TRUE;
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 6f1025e61f9e..c9c8ec120e73 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -9,7 +9,7 @@
 use Drupal\Core\Batch\BatchStorageInterface;
 use Drupal\Core\Database\IntegrityConstraintViolationException;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -33,7 +33,7 @@
 function template_preprocess_select(&$variables) {
   $element = $variables['element'];
   Element::setAttributes($element, ['id', 'name', 'size']);
-  RenderElement::setAttributes($element, ['form-select']);
+  RenderElementBase::setAttributes($element, ['form-select']);
 
   $variables['attributes'] = $element['#attributes'];
   $variables['options'] = form_select_options($element);
@@ -194,7 +194,7 @@ function form_get_options($element, $key) {
 function template_preprocess_fieldset(&$variables) {
   $element = $variables['element'];
   Element::setAttributes($element, ['id']);
-  RenderElement::setAttributes($element);
+  RenderElementBase::setAttributes($element);
   $variables['attributes'] = $element['#attributes'] ?? [];
   $variables['prefix'] = $element['#field_prefix'] ?? NULL;
   $variables['suffix'] = $element['#field_suffix'] ?? NULL;
@@ -388,7 +388,7 @@ function template_preprocess_textarea(&$variables) {
   $element = $variables['element'];
   $attributes = ['id', 'name', 'rows', 'cols', 'maxlength', 'placeholder'];
   Element::setAttributes($element, $attributes);
-  RenderElement::setAttributes($element, ['form-textarea']);
+  RenderElementBase::setAttributes($element, ['form-textarea']);
   $variables['wrapper_attributes'] = new Attribute();
   $variables['attributes'] = new Attribute($element['#attributes']);
   $variables['value'] = $element['#value'];
diff --git a/core/lib/Drupal/Core/Datetime/Element/DateElementBase.php b/core/lib/Drupal/Core/Datetime/Element/DateElementBase.php
index 24f553a41fe3..5119ffc743c7 100644
--- a/core/lib/Drupal/Core/Datetime/Element/DateElementBase.php
+++ b/core/lib/Drupal/Core/Datetime/Element/DateElementBase.php
@@ -4,12 +4,12 @@
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Render\Element\FormElement;
+use Drupal\Core\Render\Element\FormElementBase;
 
 /**
  * Provides a base class for date elements.
  */
-abstract class DateElementBase extends FormElement {
+abstract class DateElementBase extends FormElementBase {
 
   /**
    * Specifies the start and end year to use as a date range.
diff --git a/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php b/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php
index 404d1b7d23be..2162843819f4 100644
--- a/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php
@@ -79,7 +79,7 @@ public function buildResponse(Request $request, array $form, FormStateInterface
       // At this point we know callback returned a render element. If the
       // element is part of the group (#group is set on it) it won't be rendered
       // unless we remove #group from it. This is caused by
-      // \Drupal\Core\Render\Element\RenderElement::preRenderGroup(), which
+      // \Drupal\Core\Render\Element\RenderElementBase::preRenderGroup(), which
       // prevents all members of groups from being rendered directly.
       if (!empty($result['#group'])) {
         unset($result['#group']);
diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index 8253b433a120..fd2cfd04e375 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -127,7 +127,7 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
     'Drupal\Core\Render\Element\Checkbox::valueCallback',
     'Drupal\Core\Render\Element\Checkboxes::valueCallback',
     'Drupal\Core\Render\Element\Email::valueCallback',
-    'Drupal\Core\Render\Element\FormElement::valueCallback',
+    'Drupal\Core\Render\Element\FormElementBase::valueCallback',
     'Drupal\Core\Render\Element\MachineName::valueCallback',
     'Drupal\Core\Render\Element\Number::valueCallback',
     'Drupal\Core\Render\Element\PathElement::valueCallback',
@@ -1219,7 +1219,7 @@ protected function handleInputElement($form_id, &$element, FormStateInterface &$
     if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
       $value_callable = $element['#value_callback'] ?? NULL;
       if (!is_callable($value_callable)) {
-        $value_callable = '\Drupal\Core\Render\Element\FormElement::valueCallback';
+        $value_callable = '\Drupal\Core\Render\Element\FormElementBase::valueCallback';
       }
 
       if ($process_input) {
diff --git a/core/lib/Drupal/Core/Form/FormState.php b/core/lib/Drupal/Core/Form/FormState.php
index 116fe62fd0c6..69835c62229e 100644
--- a/core/lib/Drupal/Core/Form/FormState.php
+++ b/core/lib/Drupal/Core/Form/FormState.php
@@ -205,7 +205,7 @@ class FormState implements FormStateInterface {
    * the $form and $form_state variables from the initial page request to the
    * one that processes the submission. 'cache' can be set to TRUE to do this.
    * A prominent example is an Ajax-enabled form, in which
-   * \Drupal\Core\Render\Element\RenderElement::processAjaxForm()
+   * \Drupal\Core\Render\Element\RenderElementBase::processAjaxForm()
    * enables form caching for all forms that include an element with the #ajax
    * property. (The Ajax handler has no way to build the form itself, so must
    * rely on the cached version.) Note that the persistence of $form and
@@ -229,7 +229,7 @@ class FormState implements FormStateInterface {
    * The validation functions and submit functions use this array for nearly all
    * their decision making. (Note that #tree determines whether the values are a
    * flat array or an array whose structure parallels the $form array. See
-   * \Drupal\Core\Render\Element\FormElement for more information.)
+   * \Drupal\Core\Render\Element\FormElementBase for more information.)
    *
    * This property is uncacheable.
    *
diff --git a/core/lib/Drupal/Core/Plugin/PluginFormInterface.php b/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
index 27a3192e0360..380e6ae5e602 100644
--- a/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
+++ b/core/lib/Drupal/Core/Plugin/PluginFormInterface.php
@@ -26,7 +26,7 @@ interface PluginFormInterface {
    * callback and build the rest of the form in the callback. By the time the
    * callback is executed, the element's #parents and #array_parents properties
    * will have been set by the form API. For more documentation on #parents and
-   * #array_parents, see \Drupal\Core\Render\Element\FormElement.
+   * #array_parents, see \Drupal\Core\Render\Element\FormElementBase.
    *
    * @param array $form
    *   An associative array containing the initial structure of the plugin form.
diff --git a/core/lib/Drupal/Core/Render/Annotation/FormElement.php b/core/lib/Drupal/Core/Render/Annotation/FormElement.php
index 1b6baed7c7df..f83e929870ed 100644
--- a/core/lib/Drupal/Core/Render/Annotation/FormElement.php
+++ b/core/lib/Drupal/Core/Render/Annotation/FormElement.php
@@ -14,7 +14,7 @@
  *
  * @see \Drupal\Core\Render\ElementInfoManager
  * @see \Drupal\Core\Render\Element\FormElementInterface
- * @see \Drupal\Core\Render\Element\FormElement
+ * @see \Drupal\Core\Render\Element\FormElementBase
  * @see \Drupal\Core\Render\Annotation\RenderElement
  * @see plugin_api
  *
diff --git a/core/lib/Drupal/Core/Render/Annotation/RenderElement.php b/core/lib/Drupal/Core/Render/Annotation/RenderElement.php
index caf17aefcce2..c82a8512ad4a 100644
--- a/core/lib/Drupal/Core/Render/Annotation/RenderElement.php
+++ b/core/lib/Drupal/Core/Render/Annotation/RenderElement.php
@@ -16,7 +16,7 @@
  *
  * @see \Drupal\Core\Render\ElementInfoManager
  * @see \Drupal\Core\Render\Element\ElementInterface
- * @see \Drupal\Core\Render\Element\RenderElement
+ * @see \Drupal\Core\Render\Element\RenderElementBase
  * @see \Drupal\Core\Render\Annotation\FormElement
  * @see plugin_api
  *
diff --git a/core/lib/Drupal/Core/Render/Attribute/FormElement.php b/core/lib/Drupal/Core/Render/Attribute/FormElement.php
index ba41ae252da7..a9df5c13bcf6 100644
--- a/core/lib/Drupal/Core/Render/Attribute/FormElement.php
+++ b/core/lib/Drupal/Core/Render/Attribute/FormElement.php
@@ -16,7 +16,7 @@
  *
  * @see \Drupal\Core\Render\ElementInfoManager
  * @see \Drupal\Core\Render\Element\FormElementInterface
- * @see \Drupal\Core\Render\Element\FormElement
+ * @see \Drupal\Core\Render\Element\FormElementBase
  * @see \Drupal\Core\Render\Attribute\RenderElement
  * @see plugin_api
  *
diff --git a/core/lib/Drupal/Core/Render/Attribute/RenderElement.php b/core/lib/Drupal/Core/Render/Attribute/RenderElement.php
index fae4767d531d..4d3f69611a27 100644
--- a/core/lib/Drupal/Core/Render/Attribute/RenderElement.php
+++ b/core/lib/Drupal/Core/Render/Attribute/RenderElement.php
@@ -18,7 +18,7 @@
  *
  * @see \Drupal\Core\Render\ElementInfoManager
  * @see \Drupal\Core\Render\Element\ElementInterface
- * @see \Drupal\Core\Render\Element\RenderElement
+ * @see \Drupal\Core\Render\Element\RenderElementBase
  * @see \Drupal\Core\Render\Attribute\FormElement
  * @see plugin_api
  *
diff --git a/core/lib/Drupal/Core/Render/Element/Ajax.php b/core/lib/Drupal/Core/Render/Element/Ajax.php
index 1de3cf3da69f..28353c2e7b27 100644
--- a/core/lib/Drupal/Core/Render/Element/Ajax.php
+++ b/core/lib/Drupal/Core/Render/Element/Ajax.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for adding Ajax to a render element.
diff --git a/core/lib/Drupal/Core/Render/Element/Button.php b/core/lib/Drupal/Core/Render/Element/Button.php
index 3afe5ad7593d..bde0453842eb 100644
--- a/core/lib/Drupal/Core/Render/Element/Button.php
+++ b/core/lib/Drupal/Core/Render/Element/Button.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides an action button form element.
diff --git a/core/lib/Drupal/Core/Render/Element/Checkbox.php b/core/lib/Drupal/Core/Render/Element/Checkbox.php
index d8871a0dd066..e86f82da50be 100644
--- a/core/lib/Drupal/Core/Render/Element/Checkbox.php
+++ b/core/lib/Drupal/Core/Render/Element/Checkbox.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for a single checkbox.
diff --git a/core/lib/Drupal/Core/Render/Element/Checkboxes.php b/core/lib/Drupal/Core/Render/Element/Checkboxes.php
index 81e7bdfed2f8..8a7643f0e84e 100644
--- a/core/lib/Drupal/Core/Render/Element/Checkboxes.php
+++ b/core/lib/Drupal/Core/Render/Element/Checkboxes.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for a set of checkboxes.
diff --git a/core/lib/Drupal/Core/Render/Element/Color.php b/core/lib/Drupal/Core/Render/Element/Color.php
index b2c84c5a5c10..99ef21166622 100644
--- a/core/lib/Drupal/Core/Render/Element/Color.php
+++ b/core/lib/Drupal/Core/Render/Element/Color.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 use Drupal\Component\Utility\Color as ColorUtility;
 
 /**
diff --git a/core/lib/Drupal/Core/Render/Element/ComponentElement.php b/core/lib/Drupal/Core/Render/Element/ComponentElement.php
index d91aa7341579..829c5f9f5815 100644
--- a/core/lib/Drupal/Core/Render/Element/ComponentElement.php
+++ b/core/lib/Drupal/Core/Render/Element/ComponentElement.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\RenderElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 use Drupal\Core\Security\DoTrustedCallbackTrait;
 use Drupal\Core\Render\Component\Exception\InvalidComponentDataException;
 
diff --git a/core/lib/Drupal/Core/Render/Element/Container.php b/core/lib/Drupal/Core/Render/Element/Container.php
index d18b2d301f64..dfb1bd63f9ac 100644
--- a/core/lib/Drupal/Core/Render/Element/Container.php
+++ b/core/lib/Drupal/Core/Render/Element/Container.php
@@ -6,7 +6,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\RenderElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element that wraps child elements in a container.
diff --git a/core/lib/Drupal/Core/Render/Element/Date.php b/core/lib/Drupal/Core/Render/Element/Date.php
index fc0db95b6872..735add133d84 100644
--- a/core/lib/Drupal/Core/Render/Element/Date.php
+++ b/core/lib/Drupal/Core/Render/Element/Date.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for date selection.
diff --git a/core/lib/Drupal/Core/Render/Element/Details.php b/core/lib/Drupal/Core/Render/Element/Details.php
index d2901627377a..483436378791 100644
--- a/core/lib/Drupal/Core/Render/Element/Details.php
+++ b/core/lib/Drupal/Core/Render/Element/Details.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\RenderElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for a details element, similar to a fieldset.
diff --git a/core/lib/Drupal/Core/Render/Element/Dropbutton.php b/core/lib/Drupal/Core/Render/Element/Dropbutton.php
index a966e17dec76..6834c6890551 100644
--- a/core/lib/Drupal/Core/Render/Element/Dropbutton.php
+++ b/core/lib/Drupal/Core/Render/Element/Dropbutton.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for a set of links rendered as a drop-down button.
diff --git a/core/lib/Drupal/Core/Render/Element/ElementInterface.php b/core/lib/Drupal/Core/Render/Element/ElementInterface.php
index 5f4d942c8823..f7debae9efd4 100644
--- a/core/lib/Drupal/Core/Render/Element/ElementInterface.php
+++ b/core/lib/Drupal/Core/Render/Element/ElementInterface.php
@@ -22,7 +22,7 @@
  *
  * @see \Drupal\Core\Render\ElementInfoManager
  * @see \Drupal\Core\Render\Attribute\RenderElement
- * @see \Drupal\Core\Render\Element\RenderElement
+ * @see \Drupal\Core\Render\Element\RenderElementBase
  * @see plugin_api
  *
  * @ingroup theme_render
diff --git a/core/lib/Drupal/Core/Render/Element/Email.php b/core/lib/Drupal/Core/Render/Element/Email.php
index 1334f221d7ae..197b500038f3 100644
--- a/core/lib/Drupal/Core/Render/Element/Email.php
+++ b/core/lib/Drupal/Core/Render/Element/Email.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form input element for entering an email address.
diff --git a/core/lib/Drupal/Core/Render/Element/Fieldset.php b/core/lib/Drupal/Core/Render/Element/Fieldset.php
index dd614e7633c9..87d89244688b 100644
--- a/core/lib/Drupal/Core/Render/Element/Fieldset.php
+++ b/core/lib/Drupal/Core/Render/Element/Fieldset.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for a group of form elements.
diff --git a/core/lib/Drupal/Core/Render/Element/File.php b/core/lib/Drupal/Core/Render/Element/File.php
index 50f08c5fa384..6c745491f2a6 100644
--- a/core/lib/Drupal/Core/Render/Element/File.php
+++ b/core/lib/Drupal/Core/Render/Element/File.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for uploading a file.
diff --git a/core/lib/Drupal/Core/Render/Element/Form.php b/core/lib/Drupal/Core/Render/Element/Form.php
index 7859c199ab9e..29c0b2ec8a42 100644
--- a/core/lib/Drupal/Core/Render/Element/Form.php
+++ b/core/lib/Drupal/Core/Render/Element/Form.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for a form.
diff --git a/core/lib/Drupal/Core/Render/Element/FormElement.php b/core/lib/Drupal/Core/Render/Element/FormElement.php
index 5ba5e220b211..14ab865dd3b1 100644
--- a/core/lib/Drupal/Core/Render/Element/FormElement.php
+++ b/core/lib/Drupal/Core/Render/Element/FormElement.php
@@ -3,220 +3,95 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Render\BubbleableMetadata;
-use Drupal\Core\Url;
 
 /**
  * Provides a base class for form element plugins.
  *
- * Form elements are a subset of render elements, representing elements for
- * HTML forms, which can be referenced in form arrays. See the
- * @link theme_render Render API topic @endlink for an overview of render
- * arrays and render elements, and the @link form_api Form API topic @endlink
- * for an overview of forms and form arrays.
+ * @deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. use
+ *   \Drupal\Core\Render\Element\FormElementBase instead.
  *
- * The elements of form arrays are divided up into properties (whose keys
- * start with #) and children (whose keys do not start with #). The properties
- * provide data or settings that are used in rendering and form processing.
- * Some properties are specific to a particular type of form/render element,
- * some are available for any render element, and some are available for any
- * form input element. A list of the properties that are available for all form
- * elements follows; see \Drupal\Core\Render\Element\RenderElement for some
- * additional information, as well as a list of properties that are common to
- * all render elements (including form elements). Properties specific to a
- * particular element are documented on that element's class.
- *
- * Here is a list of properties that are used during the rendering and form
- * processing of form elements, besides those properties documented in
- * \Drupal\Core\Render\Element\RenderElement (for example: #prefix, #suffix):
- * - #after_build: (array) Array of callables or function names, which are
- *   called after the element is built. Arguments: $element, $form_state.
- * - #ajax: (array) Array of elements to specify Ajax behavior. See
- *   the @link ajax Ajax API topic @endlink for more information.
- * - #array_parents: (string[], read-only) Array of names of all the element's
- *   parents (including itself) in the render array. See also #parents, #tree.
- * - #default_value: Default value for the element. See also #value.
- * - #description: (string) Help or description text for the element. In an
- *   ideal user interface, the #title should be enough to describe the element,
- *   so most elements should not have a description; if you do need one, make
- *   sure it is translated. If it is not already wrapped in a safe markup
- *   object, it will be filtered for XSS safety.
- * - #disabled: (bool) If TRUE, the element is shown but does not accept
- *   user input.
- * - #element_validate: (array) Array of callables or function names, which
- *   are called to validate the input. Arguments: $element, $form_state, $form.
- * - #field_prefix: (string) Prefix to display before the HTML input element.
- *   Should be translated, normally. If it is not already wrapped in a safe
- *   markup object, will be filtered for XSS safety. Note that the contents of
- *   this prefix are wrapped in a <span> element, so the value should not
- *   contain block level HTML. Any HTML added must be valid, i.e. any tags
- *   introduced inside this prefix must also be terminated within the prefix.
- * - #field_suffix: (string) Suffix to display after the HTML input element.
- *   Should be translated, normally. If it is not already wrapped in a safe
- *   markup object, will be filtered for XSS safety. Note that the contents of
- *   this suffix are wrapped in a <span> element, so the value should not
- *   contain block level HTML. Any HTML must also be valid, i.e. any tags
- *   introduce inside this suffix must also be terminated within the suffix.
- * - #value: (mixed) A value that cannot be edited by the user.
- * - #has_garbage_value: (bool) Internal only. Set to TRUE to indicate that the
- *   #value property of an element should not be used or processed.
- * - #input: (bool, internal) Whether or not the element accepts input.
- * - #parents: (string[], read-only) Array of names of the element's parents
- *   for purposes of getting values out of $form_state. See also
- *   #array_parents, #tree.
- * - #process: (array) Array of callables or function names, which are
- *   called during form building. Arguments: $element, $form_state, $form.
- * - #processed: (bool, internal) Set to TRUE when the element is processed.
- * - #required: (bool) Whether or not input is required on the element.
- * - #states: (array) Information about JavaScript states, such as when to
- *   hide or show the element based on input on other elements.
- *   See \Drupal\Core\Form\FormHelper::processStates() for documentation.
- * - #title: (string) Title of the form element. Should be translated.
- * - #title_display: (string) Where and how to display the #title. Possible
- *   values:
- *   - before: Label goes before the element (default for most elements).
- *   - after: Label goes after the element (default for radio elements).
- *   - invisible: Label is there but is made invisible using CSS.
- *   - attribute: Make it the title attribute (hover tooltip).
- * - #tree: (bool) TRUE if the values of this element and its children should
- *   be hierarchical in $form_state; FALSE if the values should be flat.
- *   See also #parents, #array_parents.
- * - #value_callback: (callable) Callable or function name, which is called
- *   to transform the raw user input to the element's value. Arguments:
- *   $element, $input, $form_state.
- *
- * @see \Drupal\Core\Render\Attribute\FormElement
- * @see \Drupal\Core\Render\Element\FormElementInterface
- * @see \Drupal\Core\Render\ElementInfoManager
- * @see \Drupal\Core\Render\Element\RenderElement
- * @see plugin_api
- *
- * @ingroup theme_render
+ * @see https://www.drupal.org/node/3436275
  */
-abstract class FormElement extends RenderElement implements FormElementInterface {
+abstract class FormElement extends FormElementBase {
 
   /**
    * {@inheritdoc}
    */
-  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
-    return NULL;
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    @trigger_error('\Drupal\Core\Render\Element\FormElement is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
   }
 
   /**
-   * #process callback for #pattern form element property.
-   *
-   * @param array $element
-   *   An associative array containing the properties and children of the
-   *   generic input element.
-   * @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 element.
+   * {@inheritdoc}
    */
-  public static function processPattern(&$element, FormStateInterface $form_state, &$complete_form) {
-    if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) {
-      $element['#attributes']['pattern'] = $element['#pattern'];
-      $element['#element_validate'][] = [static::class, 'validatePattern'];
-    }
+  public static function setAttributes(&$element, $class = []) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::setAttributes() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::setAttributes() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    parent::setAttributes($element, $class);
+  }
 
-    return $element;
+  /**
+   * {@inheritdoc}
+   */
+  public static function preRenderGroup($element) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::preRenderGroup() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::preRenderGroup() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::preRenderGroup($element);
   }
 
   /**
-   * #element_validate callback for #pattern form element property.
-   *
-   * @param $element
-   *   An associative array containing the properties and children of the
-   *   generic form element.
-   * @param $form_state
-   *   The current state of the form.
-   * @param array $complete_form
-   *   The complete form structure.
+   * {@inheritdoc}
    */
-  public static function validatePattern(&$element, FormStateInterface $form_state, &$complete_form) {
-    if ($element['#value'] !== '') {
-      // The pattern must match the entire string and should have the same
-      // behavior as the RegExp object in ECMA 262.
-      // - Use bracket-style delimiters to avoid introducing a special delimiter
-      //   character like '/' that would have to be escaped.
-      // - Put in brackets so that the pattern can't interfere with what's
-      //   prepended and appended.
-      $pattern = '{^(?:' . $element['#pattern'] . ')$}';
+  public static function processAjaxForm(&$element, FormStateInterface $form_state, &$complete_form) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::processAjaxForm() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::processAjaxForm() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processAjaxForm($element, $form_state, $complete_form);
+  }
 
-      if (!preg_match($pattern, $element['#value'])) {
-        $form_state->setError($element, t('%name field is not in the right format.', ['%name' => $element['#title']]));
-      }
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public static function preRenderAjaxForm($element) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::preRenderAjaxForm() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::preRenderAjaxForm() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::preRenderAjaxForm($element);
   }
 
   /**
-   * Adds autocomplete functionality to elements.
-   *
-   * This sets up autocomplete functionality for elements with an
-   * #autocomplete_route_name property, using the #autocomplete_route_parameters
-   * and #autocomplete_query_parameters properties if present.
-   *
-   * For example, suppose your autocomplete route name is
-   * 'my_module.autocomplete' and its path is
-   * '/my_module/autocomplete/{a}/{b}'. In a form array, you would create a text
-   * field with properties:
-   * @code
-   * '#autocomplete_route_name' => 'my_module.autocomplete',
-   * '#autocomplete_route_parameters' => array('a' => $some_key, 'b' => $some_id),
-   * @endcode
-   * If the user types "keywords" in that field, the full path called would be:
-   * 'my_module_autocomplete/$some_key/$some_id?q=keywords'
-   *
-   * @param array $element
-   *   The form element to process. Properties used:
-   *   - #autocomplete_route_name: A route to be used as callback URL by the
-   *     autocomplete JavaScript library.
-   *   - #autocomplete_route_parameters: The parameters to be used in
-   *     conjunction with the route name.
-   *   - #autocomplete_query_parameters: The parameters to be used in
-   *     query string
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
-   * @param array $complete_form
-   *   The complete form structure.
-   *
-   * @return array
-   *   The form element.
+   * {@inheritdoc}
    */
-  public static function processAutocomplete(&$element, FormStateInterface $form_state, &$complete_form) {
-    $url = NULL;
-    $access = FALSE;
+  public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::processGroup() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::processGroup() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processGroup($element, $form_state, $complete_form);
+  }
 
-    if (!empty($element['#autocomplete_route_name'])) {
-      $parameters = $element['#autocomplete_route_parameters'] ?? [];
-      $options = [];
-      if (!empty($element['#autocomplete_query_parameters'])) {
-        $options['query'] = $element['#autocomplete_query_parameters'];
-      }
-      $url = Url::fromRoute($element['#autocomplete_route_name'], $parameters, $options)->toString(TRUE);
-      /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
-      $access_manager = \Drupal::service('access_manager');
-      $access = $access_manager->checkNamedRoute($element['#autocomplete_route_name'], $parameters, \Drupal::currentUser(), TRUE);
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::valueCallback() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::valueCallback() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::valueCallback($element, $input, $form_state);
+  }
 
-    if ($access) {
-      $metadata = BubbleableMetadata::createFromRenderArray($element);
-      if ($access->isAllowed()) {
-        $element['#attributes']['class'][] = 'form-autocomplete';
-        $metadata->addAttachments(['library' => ['core/drupal.autocomplete']]);
-        // Provide a data attribute for the JavaScript behavior to bind to.
-        $element['#attributes']['data-autocomplete-path'] = $url->getGeneratedUrl();
-        $metadata = $metadata->merge($url);
-      }
-      $metadata
-        ->merge(BubbleableMetadata::createFromObject($access))
-        ->applyTo($element);
-    }
+  /**
+   * {@inheritdoc}
+   */
+  public static function processPattern(&$element, FormStateInterface $form_state, &$complete_form) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::processPattern() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::processPattern() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processPattern($element, $form_state, $complete_form);
+  }
 
-    return $element;
+  /**
+   * {@inheritdoc}
+   */
+  public static function validatePattern(&$element, FormStateInterface $form_state, &$complete_form) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::validatePattern() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::validatePattern() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    parent::validatePattern($element, $form_state, $complete_form);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function processAutocomplete(&$element, FormStateInterface $form_state, &$complete_form) {
+    @trigger_error('\Drupal\Core\Render\Element\FormElement::processAutocomplete() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase::processAutocomplete() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processAutocomplete($element, $form_state, $complete_form);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Render/Element/FormElementBase.php b/core/lib/Drupal/Core/Render/Element/FormElementBase.php
new file mode 100644
index 000000000000..a35a67701954
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/FormElementBase.php
@@ -0,0 +1,223 @@
+<?php
+
+namespace Drupal\Core\Render\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\BubbleableMetadata;
+use Drupal\Core\Url;
+
+/**
+ * Provides a base class for form element plugins.
+ *
+ * Form elements are a subset of render elements, representing elements for
+ * HTML forms, which can be referenced in form arrays. See the
+ * @link theme_render Render API topic @endlink for an overview of render
+ * arrays and render elements, and the @link form_api Form API topic @endlink
+ * for an overview of forms and form arrays.
+ *
+ * The elements of form arrays are divided up into properties (whose keys
+ * start with #) and children (whose keys do not start with #). The properties
+ * provide data or settings that are used in rendering and form processing.
+ * Some properties are specific to a particular type of form/render element,
+ * some are available for any render element, and some are available for any
+ * form input element. A list of the properties that are available for all form
+ * elements follows; see \Drupal\Core\Render\Element\RenderElementBase for some
+ * additional information, as well as a list of properties that are common to
+ * all render elements (including form elements). Properties specific to a
+ * particular element are documented on that element's class.
+ *
+ * Here is a list of properties that are used during the rendering and form
+ * processing of form elements, besides those properties documented in
+ * \Drupal\Core\Render\Element\RenderElementBase (for example: #prefix,
+ * #suffix):
+ * - #after_build: (array) Array of callables or function names, which are
+ *   called after the element is built. Arguments: $element, $form_state.
+ * - #ajax: (array) Array of elements to specify Ajax behavior. See
+ *   the @link ajax Ajax API topic @endlink for more information.
+ * - #array_parents: (string[], read-only) Array of names of all the element's
+ *   parents (including itself) in the render array. See also #parents, #tree.
+ * - #default_value: Default value for the element. See also #value.
+ * - #description: (string) Help or description text for the element. In an
+ *   ideal user interface, the #title should be enough to describe the element,
+ *   so most elements should not have a description; if you do need one, make
+ *   sure it is translated. If it is not already wrapped in a safe markup
+ *   object, it will be filtered for XSS safety.
+ * - #disabled: (bool) If TRUE, the element is shown but does not accept
+ *   user input.
+ * - #element_validate: (array) Array of callables or function names, which
+ *   are called to validate the input. Arguments: $element, $form_state, $form.
+ * - #field_prefix: (string) Prefix to display before the HTML input element.
+ *   Should be translated, normally. If it is not already wrapped in a safe
+ *   markup object, will be filtered for XSS safety. Note that the contents of
+ *   this prefix are wrapped in a <span> element, so the value should not
+ *   contain block level HTML. Any HTML added must be valid, i.e. any tags
+ *   introduced inside this prefix must also be terminated within the prefix.
+ * - #field_suffix: (string) Suffix to display after the HTML input element.
+ *   Should be translated, normally. If it is not already wrapped in a safe
+ *   markup object, will be filtered for XSS safety. Note that the contents of
+ *   this suffix are wrapped in a <span> element, so the value should not
+ *   contain block level HTML. Any HTML must also be valid, i.e. any tags
+ *   introduce inside this suffix must also be terminated within the suffix.
+ * - #value: (mixed) A value that cannot be edited by the user.
+ * - #has_garbage_value: (bool) Internal only. Set to TRUE to indicate that the
+ *   #value property of an element should not be used or processed.
+ * - #input: (bool, internal) Whether or not the element accepts input.
+ * - #parents: (string[], read-only) Array of names of the element's parents
+ *   for purposes of getting values out of $form_state. See also
+ *   #array_parents, #tree.
+ * - #process: (array) Array of callables or function names, which are
+ *   called during form building. Arguments: $element, $form_state, $form.
+ * - #processed: (bool, internal) Set to TRUE when the element is processed.
+ * - #required: (bool) Whether or not input is required on the element.
+ * - #states: (array) Information about JavaScript states, such as when to
+ *   hide or show the element based on input on other elements.
+ *   See \Drupal\Core\Form\FormHelper::processStates() for documentation.
+ * - #title: (string) Title of the form element. Should be translated.
+ * - #title_display: (string) Where and how to display the #title. Possible
+ *   values:
+ *   - before: Label goes before the element (default for most elements).
+ *   - after: Label goes after the element (default for radio elements).
+ *   - invisible: Label is there but is made invisible using CSS.
+ *   - attribute: Make it the title attribute (hover tooltip).
+ * - #tree: (bool) TRUE if the values of this element and its children should
+ *   be hierarchical in $form_state; FALSE if the values should be flat.
+ *   See also #parents, #array_parents.
+ * - #value_callback: (callable) Callable or function name, which is called
+ *   to transform the raw user input to the element's value. Arguments:
+ *   $element, $input, $form_state.
+ *
+ * @see \Drupal\Core\Render\Attribute\FormElement
+ * @see \Drupal\Core\Render\Element\FormElementInterface
+ * @see \Drupal\Core\Render\ElementInfoManager
+ * @see \Drupal\Core\Render\Element\RenderElementBase
+ * @see plugin_api
+ *
+ * @ingroup theme_render
+ */
+abstract class FormElementBase extends RenderElementBase implements FormElementInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
+    return NULL;
+  }
+
+  /**
+   * #process callback for #pattern form element property.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic input element.
+   * @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 element.
+   */
+  public static function processPattern(&$element, FormStateInterface $form_state, &$complete_form) {
+    if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) {
+      $element['#attributes']['pattern'] = $element['#pattern'];
+      $element['#element_validate'][] = [static::class, 'validatePattern'];
+    }
+
+    return $element;
+  }
+
+  /**
+   * #element_validate callback for #pattern form element property.
+   *
+   * @param $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   */
+  public static function validatePattern(&$element, FormStateInterface $form_state, &$complete_form) {
+    if ($element['#value'] !== '') {
+      // The pattern must match the entire string and should have the same
+      // behavior as the RegExp object in ECMA 262.
+      // - Use bracket-style delimiters to avoid introducing a special delimiter
+      //   character like '/' that would have to be escaped.
+      // - Put in brackets so that the pattern can't interfere with what's
+      //   prepended and appended.
+      $pattern = '{^(?:' . $element['#pattern'] . ')$}';
+
+      if (!preg_match($pattern, $element['#value'])) {
+        $form_state->setError($element, t('%name field is not in the right format.', ['%name' => $element['#title']]));
+      }
+    }
+  }
+
+  /**
+   * Adds autocomplete functionality to elements.
+   *
+   * This sets up autocomplete functionality for elements with an
+   * #autocomplete_route_name property, using the #autocomplete_route_parameters
+   * and #autocomplete_query_parameters properties if present.
+   *
+   * For example, suppose your autocomplete route name is
+   * 'my_module.autocomplete' and its path is
+   * '/my_module/autocomplete/{a}/{b}'. In a form array, you would create a text
+   * field with properties:
+   * @code
+   * '#autocomplete_route_name' => 'my_module.autocomplete',
+   * '#autocomplete_route_parameters' => array('a' => $some_key, 'b' => $some_id),
+   * @endcode
+   * If the user types "keywords" in that field, the full path called would be:
+   * 'my_module_autocomplete/$some_key/$some_id?q=keywords'
+   *
+   * @param array $element
+   *   The form element to process. Properties used:
+   *   - #autocomplete_route_name: A route to be used as callback URL by the
+   *     autocomplete JavaScript library.
+   *   - #autocomplete_route_parameters: The parameters to be used in
+   *     conjunction with the route name.
+   *   - #autocomplete_query_parameters: The parameters to be used in
+   *     query string
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param array $complete_form
+   *   The complete form structure.
+   *
+   * @return array
+   *   The form element.
+   */
+  public static function processAutocomplete(&$element, FormStateInterface $form_state, &$complete_form) {
+    $url = NULL;
+    $access = FALSE;
+
+    if (!empty($element['#autocomplete_route_name'])) {
+      $parameters = $element['#autocomplete_route_parameters'] ?? [];
+      $options = [];
+      if (!empty($element['#autocomplete_query_parameters'])) {
+        $options['query'] = $element['#autocomplete_query_parameters'];
+      }
+      $url = Url::fromRoute($element['#autocomplete_route_name'], $parameters, $options)->toString(TRUE);
+      /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
+      $access_manager = \Drupal::service('access_manager');
+      $access = $access_manager->checkNamedRoute($element['#autocomplete_route_name'], $parameters, \Drupal::currentUser(), TRUE);
+    }
+
+    if ($access) {
+      $metadata = BubbleableMetadata::createFromRenderArray($element);
+      if ($access->isAllowed()) {
+        $element['#attributes']['class'][] = 'form-autocomplete';
+        $metadata->addAttachments(['library' => ['core/drupal.autocomplete']]);
+        // Provide a data attribute for the JavaScript behavior to bind to.
+        $element['#attributes']['data-autocomplete-path'] = $url->getGeneratedUrl();
+        $metadata = $metadata->merge($url);
+      }
+      $metadata
+        ->merge(BubbleableMetadata::createFromObject($access))
+        ->applyTo($element);
+    }
+
+    return $element;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Render/Element/FormElementInterface.php b/core/lib/Drupal/Core/Render/Element/FormElementInterface.php
index 1f22affd982f..c579e716fde5 100644
--- a/core/lib/Drupal/Core/Render/Element/FormElementInterface.php
+++ b/core/lib/Drupal/Core/Render/Element/FormElementInterface.php
@@ -14,7 +14,7 @@
  * information about render element plugins.
  *
  * @see \Drupal\Core\Render\ElementInfoManager
- * @see \Drupal\Core\Render\Element\FormElement
+ * @see \Drupal\Core\Render\Element\FormElementBase
  * @see \Drupal\Core\Render\Attribute\FormElement
  * @see plugin_api
  *
diff --git a/core/lib/Drupal/Core/Render/Element/Hidden.php b/core/lib/Drupal/Core/Render/Element/Hidden.php
index eeda8d240c22..36ba9e4842d1 100644
--- a/core/lib/Drupal/Core/Render/Element/Hidden.php
+++ b/core/lib/Drupal/Core/Render/Element/Hidden.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for an HTML 'hidden' input element.
diff --git a/core/lib/Drupal/Core/Render/Element/Html.php b/core/lib/Drupal/Core/Render/Element/Html.php
index 8957506daa80..b3bb717f3956 100644
--- a/core/lib/Drupal/Core/Render/Element/Html.php
+++ b/core/lib/Drupal/Core/Render/Element/Html.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for an entire HTML page: <html> plus its children.
diff --git a/core/lib/Drupal/Core/Render/Element/HtmlTag.php b/core/lib/Drupal/Core/Render/Element/HtmlTag.php
index 28afde49a485..b87f3b866e9c 100644
--- a/core/lib/Drupal/Core/Render/Element/HtmlTag.php
+++ b/core/lib/Drupal/Core/Render/Element/HtmlTag.php
@@ -5,7 +5,6 @@
 use Drupal\Component\Render\MarkupInterface;
 use Drupal\Component\Utility\Html as HtmlUtility;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 use Drupal\Core\Render\Markup;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Template\Attribute;
diff --git a/core/lib/Drupal/Core/Render/Element/InlineTemplate.php b/core/lib/Drupal/Core/Render/Element/InlineTemplate.php
index d6e9cf78b403..d9a60d9af79b 100644
--- a/core/lib/Drupal/Core/Render/Element/InlineTemplate.php
+++ b/core/lib/Drupal/Core/Render/Element/InlineTemplate.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element where the user supplies an in-line Twig template.
diff --git a/core/lib/Drupal/Core/Render/Element/Item.php b/core/lib/Drupal/Core/Render/Element/Item.php
index eec2bc247b3c..6d00dabcd69c 100644
--- a/core/lib/Drupal/Core/Render/Element/Item.php
+++ b/core/lib/Drupal/Core/Render/Element/Item.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a display-only form element with an optional title and description.
diff --git a/core/lib/Drupal/Core/Render/Element/Label.php b/core/lib/Drupal/Core/Render/Element/Label.php
index 7bde972b43fe..b2dbc9841a73 100644
--- a/core/lib/Drupal/Core/Render/Element/Label.php
+++ b/core/lib/Drupal/Core/Render/Element/Label.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for displaying the label for a form element.
diff --git a/core/lib/Drupal/Core/Render/Element/LanguageSelect.php b/core/lib/Drupal/Core/Render/Element/LanguageSelect.php
index c25b4830a9b1..fc18dccbb125 100644
--- a/core/lib/Drupal/Core/Render/Element/LanguageSelect.php
+++ b/core/lib/Drupal/Core/Render/Element/LanguageSelect.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for selecting a language.
diff --git a/core/lib/Drupal/Core/Render/Element/Link.php b/core/lib/Drupal/Core/Render/Element/Link.php
index 91bb5bc777bd..6aaf0b6c74b4 100644
--- a/core/lib/Drupal/Core/Render/Element/Link.php
+++ b/core/lib/Drupal/Core/Render/Element/Link.php
@@ -8,7 +8,6 @@
 use Drupal\Core\Render\Attribute\RenderElement;
 use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 use Drupal\Core\Url as CoreUrl;
 
 /**
diff --git a/core/lib/Drupal/Core/Render/Element/Number.php b/core/lib/Drupal/Core/Render/Element/Number.php
index 5fe373c7851d..f8de491a4b21 100644
--- a/core/lib/Drupal/Core/Render/Element/Number.php
+++ b/core/lib/Drupal/Core/Render/Element/Number.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 use Drupal\Component\Utility\Number as NumberUtility;
 
 /**
diff --git a/core/lib/Drupal/Core/Render/Element/Page.php b/core/lib/Drupal/Core/Render/Element/Page.php
index 44d9d6f881f4..f271c6adfcf1 100644
--- a/core/lib/Drupal/Core/Render/Element/Page.php
+++ b/core/lib/Drupal/Core/Render/Element/Page.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for the content of an HTML page.
diff --git a/core/lib/Drupal/Core/Render/Element/PageTitle.php b/core/lib/Drupal/Core/Render/Element/PageTitle.php
index 9cbef09f0d09..c56141de3480 100644
--- a/core/lib/Drupal/Core/Render/Element/PageTitle.php
+++ b/core/lib/Drupal/Core/Render/Element/PageTitle.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for the title of an HTML page.
diff --git a/core/lib/Drupal/Core/Render/Element/Pager.php b/core/lib/Drupal/Core/Render/Element/Pager.php
index f9537f895f6c..795909e5997f 100644
--- a/core/lib/Drupal/Core/Render/Element/Pager.php
+++ b/core/lib/Drupal/Core/Render/Element/Pager.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for a pager.
diff --git a/core/lib/Drupal/Core/Render/Element/Password.php b/core/lib/Drupal/Core/Render/Element/Password.php
index 767efa2d8158..35889885f42e 100644
--- a/core/lib/Drupal/Core/Render/Element/Password.php
+++ b/core/lib/Drupal/Core/Render/Element/Password.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for entering a password, with hidden text.
diff --git a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
index 6715ad0578b6..b0a9f9783ed5 100644
--- a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
+++ b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for double-input of passwords.
diff --git a/core/lib/Drupal/Core/Render/Element/Radio.php b/core/lib/Drupal/Core/Render/Element/Radio.php
index 52a4f4ca2666..159dcf34779c 100644
--- a/core/lib/Drupal/Core/Render/Element/Radio.php
+++ b/core/lib/Drupal/Core/Render/Element/Radio.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for a single radio button.
diff --git a/core/lib/Drupal/Core/Render/Element/Radios.php b/core/lib/Drupal/Core/Render/Element/Radios.php
index abe14caf5bc5..c8ccd0b3e175 100644
--- a/core/lib/Drupal/Core/Render/Element/Radios.php
+++ b/core/lib/Drupal/Core/Render/Element/Radios.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 use Drupal\Component\Utility\Html as HtmlUtility;
 
 /**
diff --git a/core/lib/Drupal/Core/Render/Element/RenderElement.php b/core/lib/Drupal/Core/Render/Element/RenderElement.php
index fbd05918e253..c37338c3219f 100644
--- a/core/lib/Drupal/Core/Render/Element/RenderElement.php
+++ b/core/lib/Drupal/Core/Render/Element/RenderElement.php
@@ -2,476 +2,64 @@
 
 namespace Drupal\Core\Render\Element;
 
-use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Plugin\PluginBase;
-use Drupal\Core\Render\BubbleableMetadata;
-use Drupal\Core\Render\Element;
-use Drupal\Core\Url;
 
 /**
  * Provides a base class for render element plugins.
  *
- * Render elements are referenced in render arrays; see the
- * @link theme_render Render API topic @endlink for an overview of render
- * arrays and render elements.
+ * @deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use
+ *   \Drupal\Core\Render\Element\RenderElementBase instead.
  *
- * The elements of render arrays are divided up into properties (whose keys
- * start with #) and children (whose keys do not start with #). The properties
- * provide data or settings that are used in rendering. Some properties are
- * specific to a particular type of render element, some are available for any
- * render element, and some are available for any form input element. A list of
- * the properties that are available for all render elements follows; the
- * properties that are for all form elements are documented on
- * \Drupal\Core\Render\Element\FormElement, and properties specific to a
- * particular element are documented on that element's class. See the
- * @link theme_render Render API topic @endlink for a list of the most
- * commonly-used properties.
- *
- * Many of the properties are strings that are displayed to users. These
- * strings, if they are literals provided by your module, should be
- * internationalized and translated; see the
- * @link i18n Internationalization topic @endlink for more information. Note
- * that although in the properties list that follows, they are designated to be
- * of type string, they would generally end up being
- * \Drupal\Core\StringTranslation\TranslatableMarkup objects instead.
- *
- * Here is the list of the properties used during the rendering of all render
- * elements:
- * - #access: (bool) Whether the element is accessible or not. When FALSE,
- *   the element is not rendered and user-submitted values are not taken
- *   into consideration.
- * - #access_callback: A callable or function name to call to check access.
- *   Argument: element.
- * - #allowed_tags: (array) Array of allowed HTML tags for XSS filtering of
- *   #markup, #prefix, #suffix, etc.
- * - #attached: (array) Array of attachments associated with the element.
- *   See the "Attaching libraries in render arrays" section of the
- *   @link theme_render Render API topic @endlink for an overview, and
- *   \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments
- *   for a list of what this can contain. Besides this list, it may also contain
- *   a 'placeholders' element; see the Placeholders section of the
- *   @link theme_render Render API topic @endlink for an overview.
- * - #attributes: (array) HTML attributes for the element. The first-level
- *   keys are the attribute names, such as 'class', and the attributes are
- *   usually given as an array of string values to apply to that attribute
- *   (the rendering system will concatenate them together into a string in
- *   the HTML output).
- * - #cache: (array) Cache information. See the Caching section of the
- *   @link theme_render Render API topic @endlink for more information.
- * - #children: (array, internal) Array of child elements of this element.
- *   Set and used during the rendering process.
- * - #create_placeholder: (bool) TRUE if the element has placeholders that
- *   are generated by #lazy_builder callbacks. Set internally during rendering
- *   in some cases. See also #attached.
- * - #defaults_loaded: (bool) Set to TRUE during rendering when the defaults
- *   for the element #type have been added to the element.
- * - #value: (mixed) A value that cannot be edited by the user.
- * - #has_garbage_value: (bool) Internal only. Set to TRUE to indicate that the
- *   #value property of an element should not be used or processed.
- * - #id: (string) The HTML ID on the element. This is automatically set for
- *   form elements, but not for all render elements; you can override the
- *   default value or add an ID by setting this property.
- * - #lazy_builder: (array) Array whose first element is a lazy building
- *   callback (callable), and whose second is an array of scalar arguments to
- *   the callback. To use lazy building, the element array must be very
- *   simple: no properties except #lazy_builder, #cache, #weight, and
- *   #create_placeholder, and no children. A lazy builder callback typically
- *   generates #markup and/or placeholders; see the Placeholders section of the
- *   @link theme_render Render API topic @endlink for information about
- *   placeholders.
- * - #markup: (string) During rendering, this will be set to the HTML markup
- *   output. It can also be set on input, as a fallback if there is no
- *   theming for the element. This will be filtered for XSS problems during
- *   rendering; see also #plain_text and #allowed_tags.
- * - #plain_text: (string) Elements can set this instead of #markup. All HTML
- *   tags will be escaped in this text, and if both #plain_text and #markup
- *   are provided, #plain_text is used.
- * - #post_render: (array) Array of callables or function names, which are
- *   called after the element is rendered. Arguments: rendered element string,
- *   children.
- * - #pre_render: (array) Array of callables or function names, which are
- *   called just before the element is rendered. Argument: $element.
- *   Return value: an altered $element.
- * - #prefix: (string) Text to render before the entire element output. See
- *   also #suffix. If it is not already wrapped in a safe markup object, will
- *   be filtered for XSS safety.
- * - #printed: (bool, internal) Set to TRUE when an element and its children
- *   have been rendered.
- * - #render_children: (bool, internal) Set to FALSE by the rendering process
- *   if the #theme call should be bypassed (normally, the theme is used to
- *   render the children). Set to TRUE by the rendering process if the children
- *   should be rendered by rendering each one separately and concatenating.
- * - #suffix: (string) Text to render after the entire element output. See
- *   also #prefix. If it is not already wrapped in a safe markup object, will
- *   be filtered for XSS safety.
- * - #theme: (string) Name of the theme hook to use to render the element.
- *   A default is generally set for elements; users of the element can
- *   override this (typically by adding __suggestion suffixes).
- * - #theme_wrappers: (array) Array of theme hooks, which are invoked
- *   after the element and children are rendered, and before #post_render
- *   functions.
- * - #type: (string) The machine name of the type of render/form element.
- * - #weight: (float) The sort order for rendering, with lower numbers coming
- *   before higher numbers. Default if not provided is zero; elements with
- *   the same weight are rendered in the order they appear in the render
- *   array.
- *
- * @see \Drupal\Core\Render\Attribute\RenderElement
- * @see \Drupal\Core\Render\ElementInterface
- * @see \Drupal\Core\Render\ElementInfoManager
- * @see plugin_api
- *
- * @ingroup theme_render
+ * @see https://www.drupal.org/node/3436275
  */
-abstract class RenderElement extends PluginBase implements ElementInterface {
+abstract class RenderElement extends RenderElementBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+  }
 
   /**
    * {@inheritdoc}
    */
   public static function setAttributes(&$element, $class = []) {
-    if (!empty($class)) {
-      if (!isset($element['#attributes']['class'])) {
-        $element['#attributes']['class'] = [];
-      }
-      $element['#attributes']['class'] = array_merge($element['#attributes']['class'], $class);
-    }
-    // This function is invoked from form element theme functions, but the
-    // rendered form element may not necessarily have been processed by
-    // \Drupal::formBuilder()->doBuildForm().
-    if (!empty($element['#required'])) {
-      $element['#attributes']['class'][] = 'required';
-      $element['#attributes']['required'] = 'required';
-      $element['#attributes']['aria-required'] = 'true';
-    }
-    if (isset($element['#parents']) && isset($element['#errors']) && !empty($element['#validated'])) {
-      $element['#attributes']['class'][] = 'error';
-      $element['#attributes']['aria-invalid'] = 'true';
-    }
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement::setAttributes() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase::setAttributes() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    parent::setAttributes($element, $class);
   }
 
   /**
-   * Adds members of this group as actual elements for rendering.
-   *
-   * @param array $element
-   *   An associative array containing the properties and children of the
-   *   element.
-   *
-   * @return array
-   *   The modified element with all group members.
+   * {@inheritdoc}
    */
   public static function preRenderGroup($element) {
-    // The element may be rendered outside of a Form API context.
-    if (!isset($element['#parents']) || !isset($element['#groups'])) {
-      return $element;
-    }
-
-    // Inject group member elements belonging to this group.
-    $parents = implode('][', $element['#parents']);
-    $children = Element::children($element['#groups'][$parents]);
-    if (!empty($children)) {
-      foreach ($children as $key) {
-        // Break references and indicate that the element should be rendered as
-        // group member.
-        $child = (array) $element['#groups'][$parents][$key];
-        $child['#group_details'] = TRUE;
-        // Inject the element as new child element.
-        $element[] = $child;
-
-        $sort = TRUE;
-      }
-      // Re-sort the element's children if we injected group member elements.
-      if (isset($sort)) {
-        $element['#sorted'] = FALSE;
-      }
-    }
-
-    if (isset($element['#group'])) {
-      // Contains form element summary functionalities.
-      $element['#attached']['library'][] = 'core/drupal.form';
-
-      $group = $element['#group'];
-      // If this element belongs to a group, but the group-holding element does
-      // not exist, we need to render it (at its original location).
-      if (!isset($element['#groups'][$group]['#group_exists'])) {
-        // Intentionally empty to clarify the flow; we simply return $element.
-      }
-      // If we injected this element into the group, then we want to render it.
-      elseif (!empty($element['#group_details'])) {
-        // Intentionally empty to clarify the flow; we simply return $element.
-      }
-      // Otherwise, this element belongs to a group and the group exists, so we do
-      // not render it.
-      elseif (Element::children($element['#groups'][$group])) {
-        $element['#printed'] = TRUE;
-      }
-    }
-
-    return $element;
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement::preRenderGroup() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase::preRenderGroup() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::preRenderGroup($element);
   }
 
   /**
-   * Form element processing handler for the #ajax form property.
-   *
-   * This method is useful for non-input elements that can be used in and
-   * outside the context of a form.
-   *
-   * @param array $element
-   *   An associative array containing the properties of the element.
-   * @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 element.
-   *
-   * @see self::preRenderAjaxForm()
+   * {@inheritdoc}
    */
   public static function processAjaxForm(&$element, FormStateInterface $form_state, &$complete_form) {
-    return static::preRenderAjaxForm($element);
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement::processAjaxForm() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase::processAjaxForm() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processAjaxForm($element, $form_state, $complete_form);
   }
 
   /**
-   * Adds Ajax information about an element to communicate with JavaScript.
-   *
-   * If #ajax is set on an element, this additional JavaScript is added to the
-   * page header to attach the Ajax behaviors. See ajax.js for more information.
-   *
-   * @param array $element
-   *   An associative array containing the properties of the element.
-   *   Properties used:
-   *   - #ajax['event']
-   *   - #ajax['prevent']
-   *   - #ajax['url']
-   *   - #ajax['httpMethod']
-   *   - #ajax['callback']
-   *   - #ajax['options']
-   *   - #ajax['wrapper']
-   *   - #ajax['parameters']
-   *   - #ajax['effect']
-   *   - #ajax['accepts']
-   *
-   * @return array
-   *   The processed element with the necessary JavaScript attached to it.
+   * {@inheritdoc}
    */
   public static function preRenderAjaxForm($element) {
-    // Skip already processed elements.
-    if (isset($element['#ajax_processed'])) {
-      return $element;
-    }
-    // Initialize #ajax_processed, so we do not process this element again.
-    $element['#ajax_processed'] = FALSE;
-
-    // Nothing to do if there are no Ajax settings.
-    if (empty($element['#ajax'])) {
-      return $element;
-    }
-
-    // Add a data attribute to disable automatic refocus after ajax call.
-    if (!empty($element['#ajax']['disable-refocus'])) {
-      $element['#attributes']['data-disable-refocus'] = "true";
-    }
-
-    // Add a data attribute to attempt to focus element that was focused before
-    // executing ajax commands.
-    if ($element['#ajax']['refocus-blur'] ?? FALSE) {
-      $element['#attributes']['data-refocus-blur'] = "true";
-    }
-
-    // Add a reasonable default event handler if none was specified.
-    if (isset($element['#ajax']) && !isset($element['#ajax']['event'])) {
-      switch ($element['#type']) {
-        case 'submit':
-        case 'button':
-        case 'image_button':
-          // Pressing the ENTER key within a textfield triggers the click event of
-          // the form's first submit button. Triggering Ajax in this situation
-          // leads to problems, like breaking autocomplete textfields, so we bind
-          // to mousedown instead of click.
-          // @see https://www.drupal.org/node/216059
-          $element['#ajax']['event'] = 'mousedown';
-          // Retain keyboard accessibility by setting 'keypress'. This causes
-          // ajax.js to trigger 'event' when SPACE or ENTER are pressed while the
-          // button has focus.
-          $element['#ajax']['keypress'] = TRUE;
-          // Binding to mousedown rather than click means that it is possible to
-          // trigger a click by pressing the mouse, holding the mouse button down
-          // until the Ajax request is complete and the button is re-enabled, and
-          // then releasing the mouse button. Set 'prevent' so that ajax.js binds
-          // an additional handler to prevent such a click from triggering a
-          // non-Ajax form submission. This also prevents a textfield's ENTER
-          // press triggering this button's non-Ajax form submission behavior.
-          if (!isset($element['#ajax']['prevent'])) {
-            $element['#ajax']['prevent'] = 'click';
-          }
-          break;
-
-        case 'password':
-        case 'textfield':
-        case 'number':
-        case 'tel':
-        case 'textarea':
-          $element['#ajax']['event'] = 'blur';
-          break;
-
-        case 'radio':
-        case 'checkbox':
-        case 'select':
-        case 'date':
-          $element['#ajax']['event'] = 'change';
-          break;
-
-        case 'link':
-          $element['#ajax']['event'] = 'click';
-          break;
-
-        default:
-          return $element;
-      }
-    }
-
-    // Attach JavaScript settings to the element.
-    if (isset($element['#ajax']['event'])) {
-      // By default, focus should return to the element focused prior to the
-      // execution of AJAX commands within event listeners attached to the blur
-      // event. This behavior can be explicitly overridden if needed.
-      if (!isset($element['#ajax']['refocus-blur'])) {
-        // The change event on text input types is triggered on blur.
-        $text_types = ['password', 'textfield', 'number', 'tel', 'textarea', 'machine_name'];
-        if ($element['#ajax']['event'] === 'blur' || ($element['#ajax']['event'] === 'change' && in_array($element['#type'], $text_types))) {
-          $element['#attributes']['data-refocus-blur'] = "true";
-        }
-      }
-
-      $element['#attached']['library'][] = 'core/internal.jquery.form';
-      $element['#attached']['library'][] = 'core/drupal.ajax';
-
-      $settings = $element['#ajax'];
-
-      // Assign default settings. When 'url' is set to NULL, ajax.js submits the
-      // Ajax request to the same URL as the form or link destination is for
-      // someone with JavaScript disabled. This is generally preferred as a way to
-      // ensure consistent server processing for js and no-js users, and Drupal's
-      // content negotiation takes care of formatting the response appropriately.
-      // However, 'url' and 'options' may be set when wanting server processing
-      // to be substantially different for a JavaScript triggered submission.
-      $settings += [
-        'url' => NULL,
-        'httpMethod' => 'POST',
-        'options' => ['query' => []],
-        'dialogType' => 'ajax',
-      ];
-      if (array_key_exists('callback', $settings) && !isset($settings['url'])) {
-        $settings['url'] = Url::fromRoute('<current>');
-        // Add all the current query parameters in order to ensure that we build
-        // the same form on the AJAX POST requests. For example,
-        // \Drupal\user\AccountForm takes query parameters into account in order
-        // to hide the password field dynamically.
-        $settings['options']['query'] += \Drupal::request()->query->all();
-        $settings['options']['query'][FormBuilderInterface::AJAX_FORM_REQUEST] = TRUE;
-      }
-
-      // @todo Legacy support. Remove in Drupal 8.
-      if (isset($settings['method']) && $settings['method'] == 'replace') {
-        $settings['method'] = 'replaceWith';
-      }
-
-      // Convert \Drupal\Core\Url object to string.
-      if (isset($settings['url']) && $settings['url'] instanceof Url) {
-        $url = $settings['url']->setOptions($settings['options'])->toString(TRUE);
-        BubbleableMetadata::createFromRenderArray($element)
-          ->merge($url)
-          ->applyTo($element);
-        $settings['url'] = $url->getGeneratedUrl();
-      }
-      else {
-        $settings['url'] = NULL;
-      }
-      unset($settings['options']);
-
-      // Add special data to $settings['submit'] so that when this element
-      // triggers an Ajax submission, Drupal's form processing can determine which
-      // element triggered it.
-      // @see _form_element_triggered_scripted_submission()
-      if (isset($settings['trigger_as'])) {
-        // An element can add a 'trigger_as' key within #ajax to make the element
-        // submit as though another one (for example, a non-button can use this
-        // to submit the form as though a button were clicked). When using this,
-        // the 'name' key is always required to identify the element to trigger
-        // as. The 'value' key is optional, and only needed when multiple elements
-        // share the same name, which is commonly the case for buttons.
-        $settings['submit']['_triggering_element_name'] = $settings['trigger_as']['name'];
-        if (isset($settings['trigger_as']['value'])) {
-          $settings['submit']['_triggering_element_value'] = $settings['trigger_as']['value'];
-        }
-        unset($settings['trigger_as']);
-      }
-      elseif (isset($element['#name'])) {
-        // Most of the time, elements can submit as themselves, in which case the
-        // 'trigger_as' key isn't needed, and the element's name is used.
-        $settings['submit']['_triggering_element_name'] = $element['#name'];
-        // If the element is a (non-image) button, its name may not identify it
-        // uniquely, in which case a match on value is also needed.
-        // @see _form_button_was_clicked()
-        if (!empty($element['#is_button']) && empty($element['#has_garbage_value'])) {
-          $settings['submit']['_triggering_element_value'] = $element['#value'];
-        }
-      }
-
-      // Convert a simple #ajax['progress'] string into an array.
-      if (isset($settings['progress']) && is_string($settings['progress'])) {
-        $settings['progress'] = ['type' => $settings['progress']];
-      }
-      // Change progress path to a full URL.
-      if (isset($settings['progress']['url']) && $settings['progress']['url'] instanceof Url) {
-        $settings['progress']['url'] = $settings['progress']['url']->toString();
-      }
-
-      $element['#attached']['drupalSettings']['ajax'][$element['#id']] = $settings;
-      $element['#attached']['drupalSettings']['ajaxTrustedUrl'][$settings['url']] = TRUE;
-
-      // Indicate that Ajax processing was successful.
-      $element['#ajax_processed'] = TRUE;
-    }
-    return $element;
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement::preRenderAjaxForm() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase::preRenderAjaxForm() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::preRenderAjaxForm($element);
   }
 
   /**
-   * Arranges elements into groups.
-   *
-   * This method is useful for non-input elements that can be used in and
-   * outside the context of a form.
-   *
-   * @param array $element
-   *   An associative array containing the properties and children of the
-   *   element. Note that $element must be taken by reference here, so processed
-   *   child elements are taken over into $form_state.
-   * @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 element.
+   * {@inheritdoc}
    */
   public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) {
-    $parents = implode('][', $element['#parents']);
-
-    // Each details element forms a new group. The #type 'vertical_tabs' basically
-    // only injects a new details element.
-    $groups = &$form_state->getGroups();
-    $groups[$parents]['#group_exists'] = TRUE;
-    $element['#groups'] = &$groups;
-
-    // Process vertical tabs group member details elements.
-    if (isset($element['#group'])) {
-      // Add this details element to the defined group (by reference).
-      $group = $element['#group'];
-      $groups[$group][] = &$element;
-    }
-
-    return $element;
+    @trigger_error('\Drupal\Core\Render\Element\RenderElement::processGroup() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase::processGroup() instead. See https://www.drupal.org/node/3436275', E_USER_DEPRECATED);
+    return parent::processGroup($element, $form_state, $complete_form);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Render/Element/RenderElementBase.php b/core/lib/Drupal/Core/Render/Element/RenderElementBase.php
new file mode 100644
index 000000000000..0ba624f743c0
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/RenderElementBase.php
@@ -0,0 +1,477 @@
+<?php
+
+namespace Drupal\Core\Render\Element;
+
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Render\BubbleableMetadata;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
+
+/**
+ * Provides a base class for render element plugins.
+ *
+ * Render elements are referenced in render arrays; see the
+ * @link theme_render Render API topic @endlink for an overview of render
+ * arrays and render elements.
+ *
+ * The elements of render arrays are divided up into properties (whose keys
+ * start with #) and children (whose keys do not start with #). The properties
+ * provide data or settings that are used in rendering. Some properties are
+ * specific to a particular type of render element, some are available for any
+ * render element, and some are available for any form input element. A list of
+ * the properties that are available for all render elements follows; the
+ * properties that are for all form elements are documented on
+ * \Drupal\Core\Render\Element\FormElementBase, and properties specific to a
+ * particular element are documented on that element's class. See the
+ * @link theme_render Render API topic @endlink for a list of the most
+ * commonly-used properties.
+ *
+ * Many of the properties are strings that are displayed to users. These
+ * strings, if they are literals provided by your module, should be
+ * internationalized and translated; see the
+ * @link i18n Internationalization topic @endlink for more information. Note
+ * that although in the properties list that follows, they are designated to be
+ * of type string, they would generally end up being
+ * \Drupal\Core\StringTranslation\TranslatableMarkup objects instead.
+ *
+ * Here is the list of the properties used during the rendering of all render
+ * elements:
+ * - #access: (bool) Whether the element is accessible or not. When FALSE,
+ *   the element is not rendered and user-submitted values are not taken
+ *   into consideration.
+ * - #access_callback: A callable or function name to call to check access.
+ *   Argument: element.
+ * - #allowed_tags: (array) Array of allowed HTML tags for XSS filtering of
+ *   #markup, #prefix, #suffix, etc.
+ * - #attached: (array) Array of attachments associated with the element.
+ *   See the "Attaching libraries in render arrays" section of the
+ *   @link theme_render Render API topic @endlink for an overview, and
+ *   \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments
+ *   for a list of what this can contain. Besides this list, it may also contain
+ *   a 'placeholders' element; see the Placeholders section of the
+ *   @link theme_render Render API topic @endlink for an overview.
+ * - #attributes: (array) HTML attributes for the element. The first-level
+ *   keys are the attribute names, such as 'class', and the attributes are
+ *   usually given as an array of string values to apply to that attribute
+ *   (the rendering system will concatenate them together into a string in
+ *   the HTML output).
+ * - #cache: (array) Cache information. See the Caching section of the
+ *   @link theme_render Render API topic @endlink for more information.
+ * - #children: (array, internal) Array of child elements of this element.
+ *   Set and used during the rendering process.
+ * - #create_placeholder: (bool) TRUE if the element has placeholders that
+ *   are generated by #lazy_builder callbacks. Set internally during rendering
+ *   in some cases. See also #attached.
+ * - #defaults_loaded: (bool) Set to TRUE during rendering when the defaults
+ *   for the element #type have been added to the element.
+ * - #value: (mixed) A value that cannot be edited by the user.
+ * - #has_garbage_value: (bool) Internal only. Set to TRUE to indicate that the
+ *   #value property of an element should not be used or processed.
+ * - #id: (string) The HTML ID on the element. This is automatically set for
+ *   form elements, but not for all render elements; you can override the
+ *   default value or add an ID by setting this property.
+ * - #lazy_builder: (array) Array whose first element is a lazy building
+ *   callback (callable), and whose second is an array of scalar arguments to
+ *   the callback. To use lazy building, the element array must be very
+ *   simple: no properties except #lazy_builder, #cache, #weight, and
+ *   #create_placeholder, and no children. A lazy builder callback typically
+ *   generates #markup and/or placeholders; see the Placeholders section of the
+ *   @link theme_render Render API topic @endlink for information about
+ *   placeholders.
+ * - #markup: (string) During rendering, this will be set to the HTML markup
+ *   output. It can also be set on input, as a fallback if there is no
+ *   theming for the element. This will be filtered for XSS problems during
+ *   rendering; see also #plain_text and #allowed_tags.
+ * - #plain_text: (string) Elements can set this instead of #markup. All HTML
+ *   tags will be escaped in this text, and if both #plain_text and #markup
+ *   are provided, #plain_text is used.
+ * - #post_render: (array) Array of callables or function names, which are
+ *   called after the element is rendered. Arguments: rendered element string,
+ *   children.
+ * - #pre_render: (array) Array of callables or function names, which are
+ *   called just before the element is rendered. Argument: $element.
+ *   Return value: an altered $element.
+ * - #prefix: (string) Text to render before the entire element output. See
+ *   also #suffix. If it is not already wrapped in a safe markup object, will
+ *   be filtered for XSS safety.
+ * - #printed: (bool, internal) Set to TRUE when an element and its children
+ *   have been rendered.
+ * - #render_children: (bool, internal) Set to FALSE by the rendering process
+ *   if the #theme call should be bypassed (normally, the theme is used to
+ *   render the children). Set to TRUE by the rendering process if the children
+ *   should be rendered by rendering each one separately and concatenating.
+ * - #suffix: (string) Text to render after the entire element output. See
+ *   also #prefix. If it is not already wrapped in a safe markup object, will
+ *   be filtered for XSS safety.
+ * - #theme: (string) Name of the theme hook to use to render the element.
+ *   A default is generally set for elements; users of the element can
+ *   override this (typically by adding __suggestion suffixes).
+ * - #theme_wrappers: (array) Array of theme hooks, which are invoked
+ *   after the element and children are rendered, and before #post_render
+ *   functions.
+ * - #type: (string) The machine name of the type of render/form element.
+ * - #weight: (float) The sort order for rendering, with lower numbers coming
+ *   before higher numbers. Default if not provided is zero; elements with
+ *   the same weight are rendered in the order they appear in the render
+ *   array.
+ *
+ * @see \Drupal\Core\Render\Attribute\RenderElement
+ * @see \Drupal\Core\Render\ElementInterface
+ * @see \Drupal\Core\Render\ElementInfoManager
+ * @see plugin_api
+ *
+ * @ingroup theme_render
+ */
+abstract class RenderElementBase extends PluginBase implements ElementInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function setAttributes(&$element, $class = []) {
+    if (!empty($class)) {
+      if (!isset($element['#attributes']['class'])) {
+        $element['#attributes']['class'] = [];
+      }
+      $element['#attributes']['class'] = array_merge($element['#attributes']['class'], $class);
+    }
+    // This function is invoked from form element theme functions, but the
+    // rendered form element may not necessarily have been processed by
+    // \Drupal::formBuilder()->doBuildForm().
+    if (!empty($element['#required'])) {
+      $element['#attributes']['class'][] = 'required';
+      $element['#attributes']['required'] = 'required';
+      $element['#attributes']['aria-required'] = 'true';
+    }
+    if (isset($element['#parents']) && isset($element['#errors']) && !empty($element['#validated'])) {
+      $element['#attributes']['class'][] = 'error';
+      $element['#attributes']['aria-invalid'] = 'true';
+    }
+  }
+
+  /**
+   * Adds members of this group as actual elements for rendering.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element.
+   *
+   * @return array
+   *   The modified element with all group members.
+   */
+  public static function preRenderGroup($element) {
+    // The element may be rendered outside of a Form API context.
+    if (!isset($element['#parents']) || !isset($element['#groups'])) {
+      return $element;
+    }
+
+    // Inject group member elements belonging to this group.
+    $parents = implode('][', $element['#parents']);
+    $children = Element::children($element['#groups'][$parents]);
+    if (!empty($children)) {
+      foreach ($children as $key) {
+        // Break references and indicate that the element should be rendered as
+        // group member.
+        $child = (array) $element['#groups'][$parents][$key];
+        $child['#group_details'] = TRUE;
+        // Inject the element as new child element.
+        $element[] = $child;
+
+        $sort = TRUE;
+      }
+      // Re-sort the element's children if we injected group member elements.
+      if (isset($sort)) {
+        $element['#sorted'] = FALSE;
+      }
+    }
+
+    if (isset($element['#group'])) {
+      // Contains form element summary functionalities.
+      $element['#attached']['library'][] = 'core/drupal.form';
+
+      $group = $element['#group'];
+      // If this element belongs to a group, but the group-holding element does
+      // not exist, we need to render it (at its original location).
+      if (!isset($element['#groups'][$group]['#group_exists'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // If we injected this element into the group, then we want to render it.
+      elseif (!empty($element['#group_details'])) {
+        // Intentionally empty to clarify the flow; we simply return $element.
+      }
+      // Otherwise, this element belongs to a group and the group exists, so we do
+      // not render it.
+      elseif (Element::children($element['#groups'][$group])) {
+        $element['#printed'] = TRUE;
+      }
+    }
+
+    return $element;
+  }
+
+  /**
+   * Form element processing handler for the #ajax form property.
+   *
+   * This method is useful for non-input elements that can be used in and
+   * outside the context of a form.
+   *
+   * @param array $element
+   *   An associative array containing the properties of the element.
+   * @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 element.
+   *
+   * @see self::preRenderAjaxForm()
+   */
+  public static function processAjaxForm(&$element, FormStateInterface $form_state, &$complete_form) {
+    return static::preRenderAjaxForm($element);
+  }
+
+  /**
+   * Adds Ajax information about an element to communicate with JavaScript.
+   *
+   * If #ajax is set on an element, this additional JavaScript is added to the
+   * page header to attach the Ajax behaviors. See ajax.js for more information.
+   *
+   * @param array $element
+   *   An associative array containing the properties of the element.
+   *   Properties used:
+   *   - #ajax['event']
+   *   - #ajax['prevent']
+   *   - #ajax['url']
+   *   - #ajax['httpMethod']
+   *   - #ajax['callback']
+   *   - #ajax['options']
+   *   - #ajax['wrapper']
+   *   - #ajax['parameters']
+   *   - #ajax['effect']
+   *   - #ajax['accepts']
+   *
+   * @return array
+   *   The processed element with the necessary JavaScript attached to it.
+   */
+  public static function preRenderAjaxForm($element) {
+    // Skip already processed elements.
+    if (isset($element['#ajax_processed'])) {
+      return $element;
+    }
+    // Initialize #ajax_processed, so we do not process this element again.
+    $element['#ajax_processed'] = FALSE;
+
+    // Nothing to do if there are no Ajax settings.
+    if (empty($element['#ajax'])) {
+      return $element;
+    }
+
+    // Add a data attribute to disable automatic refocus after ajax call.
+    if (!empty($element['#ajax']['disable-refocus'])) {
+      $element['#attributes']['data-disable-refocus'] = "true";
+    }
+
+    // Add a data attribute to attempt to focus element that was focused before
+    // executing ajax commands.
+    if ($element['#ajax']['refocus-blur'] ?? FALSE) {
+      $element['#attributes']['data-refocus-blur'] = "true";
+    }
+
+    // Add a reasonable default event handler if none was specified.
+    if (isset($element['#ajax']) && !isset($element['#ajax']['event'])) {
+      switch ($element['#type']) {
+        case 'submit':
+        case 'button':
+        case 'image_button':
+          // Pressing the ENTER key within a textfield triggers the click event of
+          // the form's first submit button. Triggering Ajax in this situation
+          // leads to problems, like breaking autocomplete textfields, so we bind
+          // to mousedown instead of click.
+          // @see https://www.drupal.org/node/216059
+          $element['#ajax']['event'] = 'mousedown';
+          // Retain keyboard accessibility by setting 'keypress'. This causes
+          // ajax.js to trigger 'event' when SPACE or ENTER are pressed while the
+          // button has focus.
+          $element['#ajax']['keypress'] = TRUE;
+          // Binding to mousedown rather than click means that it is possible to
+          // trigger a click by pressing the mouse, holding the mouse button down
+          // until the Ajax request is complete and the button is re-enabled, and
+          // then releasing the mouse button. Set 'prevent' so that ajax.js binds
+          // an additional handler to prevent such a click from triggering a
+          // non-Ajax form submission. This also prevents a textfield's ENTER
+          // press triggering this button's non-Ajax form submission behavior.
+          if (!isset($element['#ajax']['prevent'])) {
+            $element['#ajax']['prevent'] = 'click';
+          }
+          break;
+
+        case 'password':
+        case 'textfield':
+        case 'number':
+        case 'tel':
+        case 'textarea':
+          $element['#ajax']['event'] = 'blur';
+          break;
+
+        case 'radio':
+        case 'checkbox':
+        case 'select':
+        case 'date':
+          $element['#ajax']['event'] = 'change';
+          break;
+
+        case 'link':
+          $element['#ajax']['event'] = 'click';
+          break;
+
+        default:
+          return $element;
+      }
+    }
+
+    // Attach JavaScript settings to the element.
+    if (isset($element['#ajax']['event'])) {
+      // By default, focus should return to the element focused prior to the
+      // execution of AJAX commands within event listeners attached to the blur
+      // event. This behavior can be explicitly overridden if needed.
+      if (!isset($element['#ajax']['refocus-blur'])) {
+        // The change event on text input types is triggered on blur.
+        $text_types = ['password', 'textfield', 'number', 'tel', 'textarea', 'machine_name'];
+        if ($element['#ajax']['event'] === 'blur' || ($element['#ajax']['event'] === 'change' && in_array($element['#type'], $text_types))) {
+          $element['#attributes']['data-refocus-blur'] = "true";
+        }
+      }
+
+      $element['#attached']['library'][] = 'core/internal.jquery.form';
+      $element['#attached']['library'][] = 'core/drupal.ajax';
+
+      $settings = $element['#ajax'];
+
+      // Assign default settings. When 'url' is set to NULL, ajax.js submits the
+      // Ajax request to the same URL as the form or link destination is for
+      // someone with JavaScript disabled. This is generally preferred as a way to
+      // ensure consistent server processing for js and no-js users, and Drupal's
+      // content negotiation takes care of formatting the response appropriately.
+      // However, 'url' and 'options' may be set when wanting server processing
+      // to be substantially different for a JavaScript triggered submission.
+      $settings += [
+        'url' => NULL,
+        'httpMethod' => 'POST',
+        'options' => ['query' => []],
+        'dialogType' => 'ajax',
+      ];
+      if (array_key_exists('callback', $settings) && !isset($settings['url'])) {
+        $settings['url'] = Url::fromRoute('<current>');
+        // Add all the current query parameters in order to ensure that we build
+        // the same form on the AJAX POST requests. For example,
+        // \Drupal\user\AccountForm takes query parameters into account in order
+        // to hide the password field dynamically.
+        $settings['options']['query'] += \Drupal::request()->query->all();
+        $settings['options']['query'][FormBuilderInterface::AJAX_FORM_REQUEST] = TRUE;
+      }
+
+      // @todo Legacy support. Remove in Drupal 8.
+      if (isset($settings['method']) && $settings['method'] == 'replace') {
+        $settings['method'] = 'replaceWith';
+      }
+
+      // Convert \Drupal\Core\Url object to string.
+      if (isset($settings['url']) && $settings['url'] instanceof Url) {
+        $url = $settings['url']->setOptions($settings['options'])->toString(TRUE);
+        BubbleableMetadata::createFromRenderArray($element)
+          ->merge($url)
+          ->applyTo($element);
+        $settings['url'] = $url->getGeneratedUrl();
+      }
+      else {
+        $settings['url'] = NULL;
+      }
+      unset($settings['options']);
+
+      // Add special data to $settings['submit'] so that when this element
+      // triggers an Ajax submission, Drupal's form processing can determine which
+      // element triggered it.
+      // @see _form_element_triggered_scripted_submission()
+      if (isset($settings['trigger_as'])) {
+        // An element can add a 'trigger_as' key within #ajax to make the element
+        // submit as though another one (for example, a non-button can use this
+        // to submit the form as though a button were clicked). When using this,
+        // the 'name' key is always required to identify the element to trigger
+        // as. The 'value' key is optional, and only needed when multiple elements
+        // share the same name, which is commonly the case for buttons.
+        $settings['submit']['_triggering_element_name'] = $settings['trigger_as']['name'];
+        if (isset($settings['trigger_as']['value'])) {
+          $settings['submit']['_triggering_element_value'] = $settings['trigger_as']['value'];
+        }
+        unset($settings['trigger_as']);
+      }
+      elseif (isset($element['#name'])) {
+        // Most of the time, elements can submit as themselves, in which case the
+        // 'trigger_as' key isn't needed, and the element's name is used.
+        $settings['submit']['_triggering_element_name'] = $element['#name'];
+        // If the element is a (non-image) button, its name may not identify it
+        // uniquely, in which case a match on value is also needed.
+        // @see _form_button_was_clicked()
+        if (!empty($element['#is_button']) && empty($element['#has_garbage_value'])) {
+          $settings['submit']['_triggering_element_value'] = $element['#value'];
+        }
+      }
+
+      // Convert a simple #ajax['progress'] string into an array.
+      if (isset($settings['progress']) && is_string($settings['progress'])) {
+        $settings['progress'] = ['type' => $settings['progress']];
+      }
+      // Change progress path to a full URL.
+      if (isset($settings['progress']['url']) && $settings['progress']['url'] instanceof Url) {
+        $settings['progress']['url'] = $settings['progress']['url']->toString();
+      }
+
+      $element['#attached']['drupalSettings']['ajax'][$element['#id']] = $settings;
+      $element['#attached']['drupalSettings']['ajaxTrustedUrl'][$settings['url']] = TRUE;
+
+      // Indicate that Ajax processing was successful.
+      $element['#ajax_processed'] = TRUE;
+    }
+    return $element;
+  }
+
+  /**
+   * Arranges elements into groups.
+   *
+   * This method is useful for non-input elements that can be used in and
+   * outside the context of a form.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   element. Note that $element must be taken by reference here, so processed
+   *   child elements are taken over into $form_state.
+   * @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 element.
+   */
+  public static function processGroup(&$element, FormStateInterface $form_state, &$complete_form) {
+    $parents = implode('][', $element['#parents']);
+
+    // Each details element forms a new group. The #type 'vertical_tabs' basically
+    // only injects a new details element.
+    $groups = &$form_state->getGroups();
+    $groups[$parents]['#group_exists'] = TRUE;
+    $element['#groups'] = &$groups;
+
+    // Process vertical tabs group member details elements.
+    if (isset($element['#group'])) {
+      // Add this details element to the defined group (by reference).
+      $group = $element['#group'];
+      $groups[$group][] = &$element;
+    }
+
+    return $element;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Render/Element/Search.php b/core/lib/Drupal/Core/Render/Element/Search.php
index ab7c4c02d3ea..6f063e118168 100644
--- a/core/lib/Drupal/Core/Render/Element/Search.php
+++ b/core/lib/Drupal/Core/Render/Element/Search.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides an HTML5 input element with type of "search".
diff --git a/core/lib/Drupal/Core/Render/Element/Select.php b/core/lib/Drupal/Core/Render/Element/Select.php
index 3bb35226e975..5d328ace1df6 100644
--- a/core/lib/Drupal/Core/Render/Element/Select.php
+++ b/core/lib/Drupal/Core/Render/Element/Select.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for a drop-down menu or scrolling selection box.
diff --git a/core/lib/Drupal/Core/Render/Element/StatusMessages.php b/core/lib/Drupal/Core/Render/Element/StatusMessages.php
index e12aaf66530b..f0b9e25c9874 100644
--- a/core/lib/Drupal/Core/Render/Element/StatusMessages.php
+++ b/core/lib/Drupal/Core/Render/Element/StatusMessages.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a messages element.
diff --git a/core/lib/Drupal/Core/Render/Element/StatusReport.php b/core/lib/Drupal/Core/Render/Element/StatusReport.php
index e50871e8decd..fe55e9652bb2 100644
--- a/core/lib/Drupal/Core/Render/Element/StatusReport.php
+++ b/core/lib/Drupal/Core/Render/Element/StatusReport.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Creates status report page element.
diff --git a/core/lib/Drupal/Core/Render/Element/Table.php b/core/lib/Drupal/Core/Render/Element/Table.php
index 8b0a68c5640c..cc2925bcd764 100644
--- a/core/lib/Drupal/Core/Render/Element/Table.php
+++ b/core/lib/Drupal/Core/Render/Element/Table.php
@@ -5,13 +5,12 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 use Drupal\Component\Utility\Html as HtmlUtility;
 
 /**
  * Provides a render element for a table.
  *
- * Note: Although this extends FormElement, it can be used outside the
+ * Note: Although this extends FormElementBase, it can be used outside the
  * context of a form.
  *
  * Properties:
diff --git a/core/lib/Drupal/Core/Render/Element/Tel.php b/core/lib/Drupal/Core/Render/Element/Tel.php
index b4b99e5e1ccc..45b0a0e0afab 100644
--- a/core/lib/Drupal/Core/Render/Element/Tel.php
+++ b/core/lib/Drupal/Core/Render/Element/Tel.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for entering a telephone number.
diff --git a/core/lib/Drupal/Core/Render/Element/Textarea.php b/core/lib/Drupal/Core/Render/Element/Textarea.php
index 247984e73604..5e34300dc74d 100644
--- a/core/lib/Drupal/Core/Render/Element/Textarea.php
+++ b/core/lib/Drupal/Core/Render/Element/Textarea.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for input of multiple-line text.
diff --git a/core/lib/Drupal/Core/Render/Element/Textfield.php b/core/lib/Drupal/Core/Render/Element/Textfield.php
index d8e56d94a756..aa42d6bd2e80 100644
--- a/core/lib/Drupal/Core/Render/Element/Textfield.php
+++ b/core/lib/Drupal/Core/Render/Element/Textfield.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a one-line text field form element.
diff --git a/core/lib/Drupal/Core/Render/Element/Url.php b/core/lib/Drupal/Core/Render/Element/Url.php
index b346ccfcceee..efb6a7267465 100644
--- a/core/lib/Drupal/Core/Render/Element/Url.php
+++ b/core/lib/Drupal/Core/Render/Element/Url.php
@@ -6,7 +6,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for input of a URL.
diff --git a/core/lib/Drupal/Core/Render/Element/Value.php b/core/lib/Drupal/Core/Render/Element/Value.php
index 9d55da31417e..ce6f7097de78 100644
--- a/core/lib/Drupal/Core/Render/Element/Value.php
+++ b/core/lib/Drupal/Core/Render/Element/Value.php
@@ -3,7 +3,6 @@
 namespace Drupal\Core\Render\Element;
 
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for storage of internal information.
diff --git a/core/lib/Drupal/Core/Render/Element/VerticalTabs.php b/core/lib/Drupal/Core/Render/Element/VerticalTabs.php
index 6d5d57b88b1a..4c221a36b1b9 100644
--- a/core/lib/Drupal/Core/Render/Element/VerticalTabs.php
+++ b/core/lib/Drupal/Core/Render/Element/VerticalTabs.php
@@ -5,7 +5,6 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
 
 /**
  * Provides a render element for vertical tabs in a form.
diff --git a/core/lib/Drupal/Core/Render/Element/Weight.php b/core/lib/Drupal/Core/Render/Element/Weight.php
index eee1b9c81a5d..cc691dedf160 100644
--- a/core/lib/Drupal/Core/Render/Element/Weight.php
+++ b/core/lib/Drupal/Core/Render/Element/Weight.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
 
 /**
  * Provides a form element for input of a weight.
diff --git a/core/lib/Drupal/Core/Render/ElementInfoManager.php b/core/lib/Drupal/Core/Render/ElementInfoManager.php
index ec5420c507fc..a2efac850894 100644
--- a/core/lib/Drupal/Core/Render/ElementInfoManager.php
+++ b/core/lib/Drupal/Core/Render/ElementInfoManager.php
@@ -17,8 +17,8 @@
  *
  * @see \Drupal\Core\Render\Attribute\RenderElement
  * @see \Drupal\Core\Render\Attribute\FormElement
- * @see \Drupal\Core\Render\Element\RenderElement
- * @see \Drupal\Core\Render\Element\FormElement
+ * @see \Drupal\Core\Render\Element\RenderElementBase
+ * @see \Drupal\Core\Render\Element\FormElementBase
  * @see \Drupal\Core\Render\Element\ElementInterface
  * @see \Drupal\Core\Render\Element\FormElementInterface
  * @see plugin_api
diff --git a/core/lib/Drupal/Core/Render/theme.api.php b/core/lib/Drupal/Core/Render/theme.api.php
index f97ead3a200a..ac317fb4e997 100644
--- a/core/lib/Drupal/Core/Render/theme.api.php
+++ b/core/lib/Drupal/Core/Render/theme.api.php
@@ -316,11 +316,11 @@
  *   \Drupal\Core\Render\Element\ElementInterface, have the
  *   \Drupal\Core\Render\Attribute\RenderElement attribute, go in plugin
  *   namespace Element, and generally extend the
- *   \Drupal\Core\Render\Element\RenderElement base class.
+ *   \Drupal\Core\Render\Element\RenderElementBase base class.
  * - Form input elements: Render elements representing form input elements
  *   implement \Drupal\Core\Render\Element\FormElementInterface, have the
  *   \Drupal\Core\Render\Attribute\FormElement, go in plugin namespace Element,
- *   and generally extend the \Drupal\Core\Render\Element\FormElement base
+ *   and generally extend the \Drupal\Core\Render\Element\FormElementBase base
  *   class.
  * See the @link plugin_api Plugin API topic @endlink for general information
  * on plugins. You can search for classes with the RenderElement or FormElement
@@ -494,16 +494,16 @@
  * processing, and form arrays.
  *
  * Each form and render element type corresponds to an element plugin class;
- * each of them either extends \Drupal\Core\Render\Element\RenderElement
- * (render elements) or \Drupal\Core\Render\Element\FormElement (form
+ * each of them either extends \Drupal\Core\Render\Element\RenderElementBase
+ * (render elements) or \Drupal\Core\Render\Element\FormElementBase (form
  * elements). Usage and properties are documented on the individual classes,
  * and the two base classes list common properties shared by all render
  * elements and the form element subset, respectively.
  *
  * @see theme_render
  * @see form_api
- * @see \Drupal\Core\Render\Element\RenderElement
- * @see \Drupal\Core\Render\Element\FormElement
+ * @see \Drupal\Core\Render\Element\RenderElementBase
+ * @see \Drupal\Core\Render\Element\FormElementBase
  *
  * @}
  */
diff --git a/core/lib/Drupal/Core/TempStore/Element/BreakLockLink.php b/core/lib/Drupal/Core/TempStore/Element/BreakLockLink.php
index 7d58e8a217e8..4467632eeb77 100644
--- a/core/lib/Drupal/Core/TempStore/Element/BreakLockLink.php
+++ b/core/lib/Drupal/Core/TempStore/Element/BreakLockLink.php
@@ -6,7 +6,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Render\RendererInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
diff --git a/core/modules/contextual/src/Element/ContextualLinks.php b/core/modules/contextual/src/Element/ContextualLinks.php
index dc988a64af33..657c6433a4eb 100644
--- a/core/modules/contextual/src/Element/ContextualLinks.php
+++ b/core/modules/contextual/src/Element/ContextualLinks.php
@@ -5,7 +5,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\SortArray;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Url;
 
 /**
diff --git a/core/modules/contextual/src/Element/ContextualLinksPlaceholder.php b/core/modules/contextual/src/Element/ContextualLinksPlaceholder.php
index 1ccd4fc67754..b9fbcbedc020 100644
--- a/core/modules/contextual/src/Element/ContextualLinksPlaceholder.php
+++ b/core/modules/contextual/src/Element/ContextualLinksPlaceholder.php
@@ -6,7 +6,7 @@
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Component\Render\FormattableMarkup;
 
 /**
diff --git a/core/modules/field_layout/src/FieldLayoutBuilder.php b/core/modules/field_layout/src/FieldLayoutBuilder.php
index d78e0cb170a2..ccd5d2fe0edf 100644
--- a/core/modules/field_layout/src/FieldLayoutBuilder.php
+++ b/core/modules/field_layout/src/FieldLayoutBuilder.php
@@ -96,8 +96,8 @@ public function buildForm(array &$build, EntityDisplayWithLayoutInterface $displ
     $layout_definition = $this->layoutPluginManager->getDefinition($display->getLayoutId(), FALSE);
     if ($layout_definition && $fields = $this->getFields($build, $display, 'form')) {
       $fill = [];
-      $fill['#process'][] = '\Drupal\Core\Render\Element\RenderElement::processGroup';
-      $fill['#pre_render'][] = '\Drupal\Core\Render\Element\RenderElement::preRenderGroup';
+      $fill['#process'][] = '\Drupal\Core\Render\Element\RenderElementBase::processGroup';
+      $fill['#pre_render'][] = '\Drupal\Core\Render\Element\RenderElementBase::preRenderGroup';
       // Add the regions to the $build in the correct order.
       $regions = array_fill_keys($layout_definition->getRegionNames(), $fill);
 
diff --git a/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php b/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php
index 8c1d21d20d09..fca15bb05c06 100644
--- a/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php
+++ b/core/modules/field_layout/tests/src/Unit/FieldLayoutBuilderTest.php
@@ -239,12 +239,12 @@ public function testBuildForm() {
       ],
       '_field_layout' => [
         'left' => [
-          '#process' => ['\Drupal\Core\Render\Element\RenderElement::processGroup'],
-          '#pre_render' => ['\Drupal\Core\Render\Element\RenderElement::preRenderGroup'],
+          '#process' => ['\Drupal\Core\Render\Element\RenderElementBase::processGroup'],
+          '#pre_render' => ['\Drupal\Core\Render\Element\RenderElementBase::preRenderGroup'],
         ],
         'right' => [
-          '#process' => ['\Drupal\Core\Render\Element\RenderElement::processGroup'],
-          '#pre_render' => ['\Drupal\Core\Render\Element\RenderElement::preRenderGroup'],
+          '#process' => ['\Drupal\Core\Render\Element\RenderElementBase::processGroup'],
+          '#pre_render' => ['\Drupal\Core\Render\Element\RenderElementBase::preRenderGroup'],
         ],
         '#in_preview' => FALSE,
         '#settings' => [
diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php
index 00aaecd3deee..5cc5c43805a7 100644
--- a/core/modules/file/src/Element/ManagedFile.php
+++ b/core/modules/file/src/Element/ManagedFile.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\FormElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
+use Drupal\Core\Render\Element\FormElementBase;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Url;
 use Drupal\file\Entity\File;
diff --git a/core/modules/filter/src/Element/ProcessedText.php b/core/modules/filter/src/Element/ProcessedText.php
index db800ea171a6..7ec8f662458f 100644
--- a/core/modules/filter/src/Element/ProcessedText.php
+++ b/core/modules/filter/src/Element/ProcessedText.php
@@ -6,7 +6,7 @@
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Render\BubbleableMetadata;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\filter\Entity\FilterFormat;
 use Drupal\filter\Plugin\FilterInterface;
 use Drupal\filter\Render\FilteredMarkup;
diff --git a/core/modules/filter/src/Element/TextFormat.php b/core/modules/filter/src/Element/TextFormat.php
index 016f349d80c3..8cf8f2b567f9 100644
--- a/core/modules/filter/src/Element/TextFormat.php
+++ b/core/modules/filter/src/Element/TextFormat.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Url;
 
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 994531702393..d28aceb82463 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -134,7 +134,7 @@ function language_element_info_alter(&$type) {
     $type['language_select']['#process'] = array_merge($type['language_select']['#process'], [
       'language_process_language_select',
       ['Drupal\Core\Render\Element\Select', 'processSelect'],
-      ['Drupal\Core\Render\Element\RenderElement', 'processAjaxForm'],
+      ['Drupal\Core\Render\Element\RenderElementBase', 'processAjaxForm'],
     ]);
     $type['language_select']['#theme'] = 'select';
     $type['language_select']['#theme_wrappers'] = array_merge($type['language_select']['#theme_wrappers'], ['form_element']);
diff --git a/core/modules/language/src/Element/LanguageConfiguration.php b/core/modules/language/src/Element/LanguageConfiguration.php
index 5cf2097ca9c0..0f6ec33a792a 100644
--- a/core/modules/language/src/Element/LanguageConfiguration.php
+++ b/core/modules/language/src/Element/LanguageConfiguration.php
@@ -6,7 +6,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Attribute\FormElement;
-use Drupal\Core\Render\Element\FormElement as FormElementBase;
+use Drupal\Core\Render\Element\FormElementBase;
 
 /**
  * Defines an element for language configuration for a single field.
diff --git a/core/modules/layout_builder/src/Element/LayoutBuilder.php b/core/modules/layout_builder/src/Element/LayoutBuilder.php
index 451927e54032..2676d5a0dba6 100644
--- a/core/modules/layout_builder/src/Element/LayoutBuilder.php
+++ b/core/modules/layout_builder/src/Element/LayoutBuilder.php
@@ -7,7 +7,7 @@
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Render\Attribute\RenderElement;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Url;
 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
 use Drupal\layout_builder\Event\PrepareLayoutEvent;
diff --git a/core/modules/media/media.module b/core/modules/media/media.module
index d34b7e385adf..7b9f3d40aacd 100644
--- a/core/modules/media/media.module
+++ b/core/modules/media/media.module
@@ -12,7 +12,7 @@
 use Drupal\Core\Field\FieldTypeCategoryManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
-use Drupal\Core\Render\Element\RenderElement;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Template\Attribute;
@@ -310,7 +310,7 @@ function media_preprocess_media_reference_help(&$variables) {
   // incorporate parity for both.
   $element = $variables['element'];
   Element::setAttributes($element, ['id']);
-  RenderElement::setAttributes($element);
+  RenderElementBase::setAttributes($element);
   $variables['attributes'] = $element['#attributes'] ?? [];
   $variables['legend_attributes'] = new Attribute();
   $variables['header_attributes'] = new Attribute();
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index fbd26da53aae..a98ae604133c 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -342,7 +342,7 @@ abstract protected function allowedValuesDescription();
    * @param $form_state
    *   The current state of the form for the form this element belongs to.
    *
-   * @see \Drupal\Core\Render\Element\FormElement::processPattern()
+   * @see \Drupal\Core\Render\Element\FormElementBase::processPattern()
    */
   public static function validateAllowedValues($element, FormStateInterface $form_state) {
     $items = array_filter(array_map(function ($item) use ($element) {
diff --git a/core/modules/responsive_image/src/Element/ResponsiveImage.php b/core/modules/responsive_image/src/Element/ResponsiveImage.php
index 43286cfac61b..c22fab1a7625 100644
--- a/core/modules/responsive_image/src/Element/ResponsiveImage.php
+++ b/core/modules/responsive_image/src/Element/ResponsiveImage.php
@@ -3,7 +3,7 @@
 namespace Drupal\responsive_image\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 
 /**
  * Provides a responsive image element.
diff --git a/core/modules/system/src/Element/StatusReportPage.php b/core/modules/system/src/Element/StatusReportPage.php
index 5d6250f723b4..f10ecd79293a 100644
--- a/core/modules/system/src/Element/StatusReportPage.php
+++ b/core/modules/system/src/Element/StatusReportPage.php
@@ -3,7 +3,7 @@
 namespace Drupal\system\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Render\Element\StatusReport;
 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
 
diff --git a/core/modules/system/templates/container.html.twig b/core/modules/system/templates/container.html.twig
index 6cb299bfc9d3..8a94e31722c4 100644
--- a/core/modules/system/templates/container.html.twig
+++ b/core/modules/system/templates/container.html.twig
@@ -5,9 +5,9 @@
  *
  * Used for grouped form items. Can also be used as a theme wrapper for any
  * renderable element, to surround it with a <div> and HTML attributes.
- * See \Drupal\Core\Render\Element\RenderElement for more
+ * See \Drupal\Core\Render\Element\RenderElementBase for more
  * information on the #theme_wrappers render array property, and
- * \Drupal\Core\Render\Element\container for usage of the container render
+ * \Drupal\Core\Render\Element\Container for usage of the container render
  * element.
  *
  * Available variables:
diff --git a/core/modules/system/tests/modules/element_info_test/src/Element/Deprecated.php b/core/modules/system/tests/modules/element_info_test/src/Element/Deprecated.php
index 0e6da051a356..a6741fbd0878 100644
--- a/core/modules/system/tests/modules/element_info_test/src/Element/Deprecated.php
+++ b/core/modules/system/tests/modules/element_info_test/src/Element/Deprecated.php
@@ -3,7 +3,7 @@
 namespace Drupal\element_info_test\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 
 /**
  * Provides deprecated render element for testing.
diff --git a/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsFormElement.php b/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsFormElement.php
new file mode 100644
index 000000000000..07c70bda4423
--- /dev/null
+++ b/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsFormElement.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\element_info_test\Element;
+
+use Drupal\Core\Render\Attribute\FormElement;
+use Drupal\Core\Render\Element\FormElement as FormElementDeprecated;
+
+/**
+ * Provides render element that extends deprecated FormElement for testing.
+ *
+ * @phpstan-ignore-next-line
+ */
+#[FormElement('deprecated_extends_form')]
+class DeprecatedExtendsFormElement extends FormElementDeprecated {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    return [];
+  }
+
+}
diff --git a/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsRenderElement.php b/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsRenderElement.php
new file mode 100644
index 000000000000..3eb8e9beef23
--- /dev/null
+++ b/core/modules/system/tests/modules/element_info_test/src/Element/DeprecatedExtendsRenderElement.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\element_info_test\Element;
+
+use Drupal\Core\Render\Attribute\RenderElement;
+use Drupal\Core\Render\Element\RenderElement as RenderElementDeprecated;
+
+/**
+ * Provides render element that extends deprecated RenderElement for testing.
+ *
+ * @phpstan-ignore-next-line
+ */
+#[RenderElement('deprecated_extends_render')]
+class DeprecatedExtendsRenderElement extends RenderElementDeprecated {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    return [];
+  }
+
+}
diff --git a/core/modules/toolbar/src/Element/Toolbar.php b/core/modules/toolbar/src/Element/Toolbar.php
index d13ec8cebbb5..c29c3ca05bc8 100644
--- a/core/modules/toolbar/src/Element/Toolbar.php
+++ b/core/modules/toolbar/src/Element/Toolbar.php
@@ -4,7 +4,7 @@
 
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Render\Element;
 
 /**
diff --git a/core/modules/toolbar/src/Element/ToolbarItem.php b/core/modules/toolbar/src/Element/ToolbarItem.php
index 6c57973e5fbd..4ac5ca9750ea 100644
--- a/core/modules/toolbar/src/Element/ToolbarItem.php
+++ b/core/modules/toolbar/src/Element/ToolbarItem.php
@@ -3,7 +3,7 @@
 namespace Drupal\toolbar\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Core\Url;
 
 /**
diff --git a/core/modules/views/src/Element/View.php b/core/modules/views/src/Element/View.php
index 0171105d2c3f..a5ef48b9eaad 100644
--- a/core/modules/views/src/Element/View.php
+++ b/core/modules/views/src/Element/View.php
@@ -3,7 +3,7 @@
 namespace Drupal\views\Element;
 
 use Drupal\Core\Render\Attribute\RenderElement;
-use Drupal\Core\Render\Element\RenderElement as RenderElementBase;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\views\Exception\ViewRenderElementException;
 use Drupal\views\Views;
 
diff --git a/core/tests/Drupal/KernelTests/Core/Render/Element/DeprecatedElementTest.php b/core/tests/Drupal/KernelTests/Core/Render/Element/DeprecatedElementTest.php
index 916becbd9878..f2db83c0617c 100644
--- a/core/tests/Drupal/KernelTests/Core/Render/Element/DeprecatedElementTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Render/Element/DeprecatedElementTest.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\KernelTests\Core\Render\Element;
 
+use Drupal\Core\Form\FormState;
+use Drupal\element_info_test\Element\DeprecatedExtendsFormElement;
+use Drupal\element_info_test\Element\DeprecatedExtendsRenderElement;
 use Drupal\KernelTests\KernelTestBase;
 
 /**
@@ -19,10 +22,23 @@ class DeprecatedElementTest extends KernelTestBase {
    */
   public function testBuildInfo() {
     $info_manager = $this->container->get('plugin.manager.element_info');
+    $element_names = [
+      'deprecated',
+      'deprecated_extends_render',
+    ];
+    foreach ($element_names as $element_name) {
+      $this->assertSame([
+        '#type' => $element_name,
+        '#defaults_loaded' => TRUE,
+      ], $info_manager->getInfo($element_name));
+    }
+
     $this->assertSame([
-      '#type' => 'deprecated',
+      '#input' => TRUE,
+      '#value_callback' => [DeprecatedExtendsFormElement::class, 'valueCallback'],
+      '#type' => 'deprecated_extends_form',
       '#defaults_loaded' => TRUE,
-    ], $info_manager->getInfo('deprecated'));
+    ], $info_manager->getInfo('deprecated_extends_form'));
 
     // Ensure the constructor is triggering a deprecation error.
     $previous_error_handler = set_error_handler(function ($severity, $message, $file, $line) use (&$previous_error_handler) {
@@ -42,6 +58,84 @@ public function testBuildInfo() {
     catch (\ErrorException $e) {
       $this->assertSame('Drupal\element_info_test\Element\Deprecated is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3068104', $e->getMessage());
     }
+
+    try {
+      $info_manager->createInstance('deprecated_extends_form');
+      $this->fail('No deprecation error triggered.');
+    }
+    catch (\ErrorException $e) {
+      $this->assertSame('\Drupal\Core\Render\Element\FormElement is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\FormElementBase instead. See https://www.drupal.org/node/3436275', $e->getMessage());
+    }
+
+    try {
+      $info_manager->createInstance('deprecated_extends_render');
+      $this->fail('No deprecation error triggered.');
+    }
+    catch (\ErrorException $e) {
+      $this->assertSame('\Drupal\Core\Render\Element\RenderElement is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\Core\Render\Element\RenderElementBase instead. See https://www.drupal.org/node/3436275', $e->getMessage());
+    }
+
+    restore_error_handler();
+  }
+
+  /**
+   * Test use of static methods trigger deprecations.
+   */
+  public function testDeprecatedStaticMethods(): void {
+    $previous_error_handler = set_error_handler(function ($severity, $message, $file, $line) use (&$previous_error_handler) {
+      // Convert deprecation error into a catchable exception.
+      if ($severity === E_USER_DEPRECATED) {
+        throw new \ErrorException($message, 0, $severity, $file, $line);
+      }
+      if ($previous_error_handler) {
+        return $previous_error_handler($severity, $message, $file, $line);
+      }
+    });
+
+    $element = [];
+    $form_state = new FormState();
+    $complete_form = [];
+    $static_methods_render = [
+      'setAttributes' => [$element],
+      'preRenderGroup' => [$element],
+      'processAjaxForm' => [$element, $form_state, $complete_form],
+      'preRenderAjaxForm' => [$element],
+      'processGroup' => [$element, $form_state, $complete_form],
+    ];
+
+    $static_methods_form = [
+      'valueCallback' => [$element, FALSE, $form_state],
+      'processPattern' => [$element, $form_state, $complete_form],
+      'validatePattern' => [$element, $form_state, $complete_form],
+      'processAutocomplete' => [$element, $form_state, $complete_form],
+    ];
+
+    $class_names = [
+      DeprecatedExtendsRenderElement::class,
+      DeprecatedExtendsFormElement::class,
+    ];
+    foreach ($class_names as $class_name) {
+      foreach ($static_methods_render as $method_name => $arguments) {
+        try {
+          $class_name::$method_name(...$arguments);
+          $this->fail('No deprecation error triggered.');
+        }
+        catch (\ErrorException $e) {
+          $parent_class = get_parent_class($class_name);
+          $this->assertSame("\\{$parent_class}::{$method_name}() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \\{$parent_class}Base::{$method_name}() instead. See https://www.drupal.org/node/3436275", $e->getMessage());
+        }
+      }
+    }
+    foreach ($static_methods_form as $method_name => $arguments) {
+      try {
+        DeprecatedExtendsFormElement::$method_name(...$arguments);
+        $this->fail('No deprecation error triggered.');
+      }
+      catch (\ErrorException $e) {
+        $this->assertSame("\\Drupal\\Core\\Render\\Element\\FormElement::{$method_name}() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \\Drupal\\Core\\Render\\Element\\FormElementBase::{$method_name}() instead. See https://www.drupal.org/node/3436275", $e->getMessage());
+      }
+    }
+
     restore_error_handler();
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Render/Element/RenderElementTest.php b/core/tests/Drupal/Tests/Core/Render/Element/RenderElementTest.php
index 6ee1d37f1664..4e9a0667398a 100644
--- a/core/tests/Drupal/Tests/Core/Render/Element/RenderElementTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/Element/RenderElementTest.php
@@ -7,13 +7,13 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\GeneratedUrl;
-use Drupal\Core\Render\Element\RenderElement;
+use Drupal\Core\Render\Element\RenderElementBase;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
- * @coversDefaultClass \Drupal\Core\Render\Element\RenderElement
+ * @coversDefaultClass \Drupal\Core\Render\Element\RenderElementBase
  * @group Render
  */
 class RenderElementTest extends UnitTestCase {
@@ -69,7 +69,7 @@ public function testPreRenderAjaxForm() {
       ],
     ];
 
-    $element = RenderElement::preRenderAjaxForm($element);
+    $element = RenderElementBase::preRenderAjaxForm($element);
 
     $this->assertTrue($element['#ajax_processed']);
     $this->assertEquals($url, $element['#attached']['drupalSettings']['ajax']['test']['url']);
@@ -105,7 +105,7 @@ public function testPreRenderAjaxFormWithQueryOptions() {
       ],
     ];
 
-    $element = RenderElement::preRenderAjaxForm($element);
+    $element = RenderElementBase::preRenderAjaxForm($element);
 
     $this->assertTrue($element['#ajax_processed']);
     $this->assertEquals($url, $element['#attached']['drupalSettings']['ajax']['test']['url']);
diff --git a/core/themes/stable9/templates/form/container.html.twig b/core/themes/stable9/templates/form/container.html.twig
index 0da6c388d022..0e35d503f0ae 100644
--- a/core/themes/stable9/templates/form/container.html.twig
+++ b/core/themes/stable9/templates/form/container.html.twig
@@ -5,9 +5,9 @@
  *
  * Used for grouped form items. Can also be used as a theme wrapper for any
  * renderable element, to surround it with a <div> and HTML attributes.
- * See \Drupal\Core\Render\Element\RenderElement for more
+ * See \Drupal\Core\Render\Element\RenderElementBase for more
  * information on the #theme_wrappers render array property, and
- * \Drupal\Core\Render\Element\container for usage of the container render
+ * \Drupal\Core\Render\Element\Container for usage of the container render
  * element.
  *
  * Available variables:
diff --git a/core/themes/starterkit_theme/templates/form/container.html.twig b/core/themes/starterkit_theme/templates/form/container.html.twig
index 0da6c388d022..0e35d503f0ae 100644
--- a/core/themes/starterkit_theme/templates/form/container.html.twig
+++ b/core/themes/starterkit_theme/templates/form/container.html.twig
@@ -5,9 +5,9 @@
  *
  * Used for grouped form items. Can also be used as a theme wrapper for any
  * renderable element, to surround it with a <div> and HTML attributes.
- * See \Drupal\Core\Render\Element\RenderElement for more
+ * See \Drupal\Core\Render\Element\RenderElementBase for more
  * information on the #theme_wrappers render array property, and
- * \Drupal\Core\Render\Element\container for usage of the container render
+ * \Drupal\Core\Render\Element\Container for usage of the container render
  * element.
  *
  * Available variables:
-- 
GitLab