diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 5c61f22..0a237ac 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -492,8 +492,8 @@ function template_preprocess_datetime_wrapper(&$variables) {
   }
 
   $variables['required'] = FALSE;
-  // For required datetime fields a 'form-required' class is appended to the
-  // label attributes.
+  // For required datetime fields 'form-required' & 'js-form-required' class
+  // are appended to the label attributes.
   if (!empty($element['#required'])) {
     $variables['required'] = TRUE;
   }
@@ -1111,7 +1111,7 @@ function template_preprocess_feed_icon(&$variables) {
 function theme_indentation($variables) {
   $output = '';
   for ($n = 0; $n < $variables['size']; $n++) {
-    $output .= '<div class="js-indentation">&nbsp;</div>';
+    $output .= '<div class="js-indentation indentation">&nbsp;</div>';
   }
   return $output;
 }
@@ -1631,6 +1631,7 @@ function template_preprocess_field_multiple_value_form(&$variables) {
     $order_class = $element['#field_name'] . '-delta-order';
     $header_attributes = new Attribute(array('class' => array('label')));
     if (!empty($element['#required'])) {
+      $header_attributes['class'][] = 'js-form-required';
       $header_attributes['class'][] = 'form-required';
     }
     $header = array(
diff --git a/core/lib/Drupal/Core/Render/Element/Details.php b/core/lib/Drupal/Core/Render/Element/Details.php
index c45810e..cf57bc7 100644
--- a/core/lib/Drupal/Core/Render/Element/Details.php
+++ b/core/lib/Drupal/Core/Render/Element/Details.php
@@ -54,9 +54,9 @@ public function getInfo() {
   public static function preRenderDetails($element) {
     Element::setAttributes($element, array('id'));
 
-    // The .form-wrapper class is required for #states to treat details like
+    // The .js-form-wrapper class is required for #states to treat details like
     // containers.
-    static::setAttributes($element, array('form-wrapper'));
+    static::setAttributes($element, array('js-form-wrapper', 'form-wrapper'));
 
     // Collapsible details.
     $element['#attached']['library'][] = 'core/drupal.collapse';
diff --git a/core/misc/states.js b/core/misc/states.js
index 680e86e..c520d7c 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -509,7 +509,7 @@
     if (e.trigger) {
       $(e.target)
         .prop('disabled', e.value)
-        .closest('.form-item, .form-submit, .form-wrapper').toggleClass('form-disabled', e.value)
+        .closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggleClass('form-disabled', e.value)
         .find('select, input, textarea').prop('disabled', e.value);
 
       // Note: WebKit nightlies don't reflect that change correctly.
@@ -520,21 +520,21 @@
   $(document).on('state:required', function (e) {
     if (e.trigger) {
       if (e.value) {
-        var $label = $(e.target).attr({'required': 'required', 'aria-required': 'aria-required'}).closest('.form-item, .form-wrapper').find('label');
+        var $label = $(e.target).attr({'required': 'required', 'aria-required': 'aria-required'}).closest('.js-form-item, .js-form-wrapper').find('label');
         // Avoids duplicate required markers on initialization.
-        if (!$label.hasClass('form-required').length) {
-          $label.addClass('form-required');
+        if (!$label.hasClass('js-form-required').length) {
+          $label.addClass('js-form-required form-required');
         }
       }
       else {
-        $(e.target).removeAttr('required aria-required').closest('.form-item, .form-wrapper').find('label.form-required').removeClass('form-required');
+        $(e.target).removeAttr('required aria-required').closest('.js-form-item, .js-form-wrapper').find('label.js-form-required').removeClass('js-form-required form-required');
       }
     }
   });
 
   $(document).on('state:visible', function (e) {
     if (e.trigger) {
-      $(e.target).closest('.form-item, .form-submit, .form-wrapper').toggle(e.value);
+      $(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggle(e.value);
     }
   });
 
diff --git a/core/modules/datetime/src/Tests/DateTimeFieldTest.php b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
index e2223dc..b7a2988 100644
--- a/core/modules/datetime/src/Tests/DateTimeFieldTest.php
+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -100,7 +100,7 @@ function testDateField() {
     // Display creation form.
     $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
-    $this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]/h4[contains(@class, "form-required")]', TRUE, 'Required markup found');
+    $this->assertFieldByXPath('//*[@id="edit-' . $field_name . '-wrapper"]/h4[contains(@class, "js-form-required")]', TRUE, 'Required markup found');
     $this->assertNoFieldByName("{$field_name}[0][value][time]", '', 'Time element not found.');
 
     // Submit a valid date and ensure it is accepted.
diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js
index 6394c3e..36b2ebe 100644
--- a/core/modules/field_ui/field_ui.js
+++ b/core/modules/field_ui/field_ui.js
@@ -19,7 +19,7 @@
           '.form-item-label label,' +
           '.form-item-field-name label,' +
           '.form-item-existing-storage-label label')
-          .addClass('form-required');
+          .addClass('js-form-required form-required');
 
         var $newFieldType = $form.find('select[name="new_storage_type"]');
         var $existingStorageName = $form.find('select[name="existing_storage_name"]');
diff --git a/core/modules/field_ui/src/Form/EntityDisplayFormBase.php b/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
index 94feeff..c411683 100644
--- a/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
+++ b/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
@@ -307,7 +307,7 @@ protected function buildFieldRow(FieldDefinitionInterface $field_definition, arr
           '#title_display' => 'invisible',
           '#options' => array_combine($regions, $regions),
           '#empty_value' => '',
-          '#attributes' => array('class' => array('field-parent')),
+          '#attributes' => array('class' => array('js-field-parent', 'field-parent')),
           '#parents' => array('fields', $field_name, 'parent'),
         ),
         'hidden_name' => array(
@@ -486,7 +486,7 @@ protected function buildExtraFieldRow($field_id, $extra_field) {
           '#title_display' => 'invisible',
           '#options' => array_combine($regions, $regions),
           '#empty_value' => '',
-          '#attributes' => array('class' => array('field-parent')),
+          '#attributes' => array('class' => array('js-field-parent', 'field-parent')),
           '#parents' => array('fields', $field_id, 'parent'),
         ),
         'hidden_name' => array(
diff --git a/core/modules/image/src/Tests/ImageFieldValidateTest.php b/core/modules/image/src/Tests/ImageFieldValidateTest.php
index e6afc32..f803b4b 100644
--- a/core/modules/image/src/Tests/ImageFieldValidateTest.php
+++ b/core/modules/image/src/Tests/ImageFieldValidateTest.php
@@ -68,11 +68,11 @@ function testRequiredAttributes() {
     $this->uploadNodeImage($image, $field_name, 'article');
 
     // Look for form-required for the alt text.
-    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
+    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-alt" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-alt"]');
 
     $this->assertTrue(isset($elements[0]),'Required marker is shown for the required alt text.');
 
-    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
+    $elements = $this->xpath('//label[@for="edit-' . $field_name . '-0-title" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-' . $field_name . '-0-title"]');
 
     $this->assertTrue(isset($elements[0]), 'Required marker is shown for the required title text.');
 
diff --git a/core/modules/system/css/system.module.css b/core/modules/system/css/system.module.css
index 0359e4b..b38c5e5 100644
--- a/core/modules/system/css/system.module.css
+++ b/core/modules/system/css/system.module.css
@@ -134,14 +134,14 @@ a.tabledrag-handle:focus .handle {
 .touch .draggable.drag a.tabledrag-handle .handle {
   background-position: 50% -32px;
 }
-div.js-indentation {
+.indentation {
   float: left; /* LTR */
   height: 1.7em;
   margin: -0.4em 0.2em -0.4em -0.4em; /* LTR */
   padding: 0.42em 0 0.42em 0.6em; /* LTR */
   width: 20px;
 }
-[dir="rtl"] div.js-indentation {
+[dir="rtl"] .indentation {
   float: right;
   margin: -0.4em -0.4em -0.4em 0.2em;
   padding: 0.42em 0.6em 0.42em 0;
diff --git a/core/modules/system/src/Tests/Form/ElementsLabelsTest.php b/core/modules/system/src/Tests/Form/ElementsLabelsTest.php
index dbf13d2..c0f21f3 100644
--- a/core/modules/system/src/Tests/Form/ElementsLabelsTest.php
+++ b/core/modules/system/src/Tests/Form/ElementsLabelsTest.php
@@ -53,16 +53,16 @@ function testFormLabels() {
 
     // Exercise various defaults for textboxes and modifications to ensure
     // appropriate override and correct behavior.
-    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required" and @class="form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
+    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
     $this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.');
 
-    $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required" and @class="form-required"]');
+    $elements = $this->xpath('//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required" and @class="js-form-required form-required"]');
     $this->assertTrue(isset($elements[0]), 'Label tag with required marker precedes required textfield with no title.');
 
     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]');
     $this->assertTrue(isset($elements[0]), 'Label preceding field and label class is visually-hidden.');
 
-    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title"]/preceding-sibling::span[@class="form-required"]');
+    $elements = $this->xpath('//input[@id="edit-form-textfield-test-title"]/preceding-sibling::span[@class="js-form-required form-required"]');
     $this->assertFalse(isset($elements[0]), 'No required marker on non-required field.');
 
     $elements = $this->xpath('//input[@id="edit-form-textfield-test-title-after"]/following-sibling::label[@for="edit-form-textfield-test-title-after" and @class="option"]');
diff --git a/core/modules/system/src/Tests/Form/FormTest.php b/core/modules/system/src/Tests/Form/FormTest.php
index e82002b..b824dcf 100644
--- a/core/modules/system/src/Tests/Form/FormTest.php
+++ b/core/modules/system/src/Tests/Form/FormTest.php
@@ -96,7 +96,7 @@ function testRequiredFields() {
     $elements['file']['empty_values'] = $empty_strings;
 
     // Regular expression to find the expected marker on required elements.
-    $required_marker_preg = '@<.*?class=".*?form-required.*?">@';
+    $required_marker_preg = '@<.*?class=".*?js-form-required.*form-required.*?">@';
     // Go through all the elements and all the empty values for them.
     foreach ($elements as $type => $data) {
       foreach ($data['empty_values'] as $key => $empty) {
diff --git a/core/modules/system/templates/container.html.twig b/core/modules/system/templates/container.html.twig
index 6fb8159..2f71632 100644
--- a/core/modules/system/templates/container.html.twig
+++ b/core/modules/system/templates/container.html.twig
@@ -17,4 +17,9 @@
  * @ingroup themeable
  */
 #}
-<div{{ attributes.addClass(has_parent ? 'form-wrapper') }}>{{ children }}</div>
+{%
+  set classes = [
+    has_parent ? 'js-form-wrapper',
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>{{ children }}</div>
diff --git a/core/modules/system/templates/datetime-wrapper.html.twig b/core/modules/system/templates/datetime-wrapper.html.twig
index 443b5b3..62a4b9d 100644
--- a/core/modules/system/templates/datetime-wrapper.html.twig
+++ b/core/modules/system/templates/datetime-wrapper.html.twig
@@ -17,7 +17,7 @@
 #}
 {%
   set title_classes = [
-    required ? 'form-required',
+    required ? 'js-form-required',
   ]
 %}
 {% if title %}
diff --git a/core/modules/system/templates/fieldset.html.twig b/core/modules/system/templates/fieldset.html.twig
index ab6796c..cb8b41b 100644
--- a/core/modules/system/templates/fieldset.html.twig
+++ b/core/modules/system/templates/fieldset.html.twig
@@ -21,24 +21,29 @@
  * @ingroup themeable
  */
 #}
-<fieldset{{ attributes.addClass('form-item', 'form-wrapper') }}>
+{%
+  set classes = [
+    'js-form-item',
+    'js-form-wrapper',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
   {%
     set legend_span_classes = [
-      'fieldset-legend',
-      required ? 'form-required',
+      required ? 'js-form-required',
     ]
   %}
   {#  Always wrap fieldset legends in a SPAN for CSS positioning. #}
   <legend{{ legend.attributes }}>
     <span{{ legend_span.attributes.addClass(legend_span_classes) }}>{{ legend.title }}</span>
   </legend>
-  <div class="fieldset-wrapper">
+  <div>
     {% if prefix %}
-      <span class="field-prefix">{{ prefix }}</span>
+      <span>{{ prefix }}</span>
     {% endif %}
     {{ children }}
     {% if suffix %}
-      <span class="field-suffix">{{ suffix }}</span>
+      <span>{{ suffix }}</span>
     {% endif %}
     {% if description.content %}
       <div{{ description.attributes.addClass('description') }}>{{ description.content }}</div>
diff --git a/core/modules/system/templates/form-element-label.html.twig b/core/modules/system/templates/form-element-label.html.twig
index 6ececd9..a86ade4 100644
--- a/core/modules/system/templates/form-element-label.html.twig
+++ b/core/modules/system/templates/form-element-label.html.twig
@@ -16,9 +16,8 @@
 #}
 {%
   set classes = [
-    title_display == 'after' ? 'option',
     title_display == 'invisible' ? 'visually-hidden',
-    required ? 'form-required',
+    required ? 'js-form-required',
   ]
 %}
 {% if title is not empty or required -%}
diff --git a/core/modules/taxonomy/src/Tests/TaxonomyTermIndentationTest.php b/core/modules/taxonomy/src/Tests/TaxonomyTermIndentationTest.php
index 0e40c1e..ba223a7 100644
--- a/core/modules/taxonomy/src/Tests/TaxonomyTermIndentationTest.php
+++ b/core/modules/taxonomy/src/Tests/TaxonomyTermIndentationTest.php
@@ -53,7 +53,7 @@ function testTermIndentation() {
 
     // Submit the edited form and check for HTML indentation element presence.
     $this->drupalPostForm('admin/structure/taxonomy/manage/' . $this->vocabulary->get('vid') . '/overview', $edit, t('Save'));
-    $this->assertPattern('|<div class="js-indentation">&nbsp;</div>|');
+    $this->assertPattern('|<div class="js-indentation indentation">&nbsp;</div>|');
 
     // Check explicitly that term 2's parent is term 1.
     $parents = taxonomy_term_load_parents($term2->id());
@@ -69,7 +69,7 @@ function testTermIndentation() {
 
     $this->drupalPostForm('admin/structure/taxonomy/manage/' . $this->vocabulary->get('vid' ) . '/overview', $edit, t('Save'));
     // All terms back at the root level, no identation should be present.
-    $this->assertNoPattern('|<div class="js-indentation">&nbsp;</div>|');
+    $this->assertNoPattern('|<div class="js-indentation indentation">&nbsp;</div>|');
 
     // Check explicitly that term 2 has no parents.
     \Drupal::entityManager()->getStorage('taxonomy_term')->resetCache();
diff --git a/core/modules/views/src/Tests/ViewElementTest.php b/core/modules/views/src/Tests/ViewElementTest.php
index e9c8105..bd17747 100644
--- a/core/modules/views/src/Tests/ViewElementTest.php
+++ b/core/modules/views/src/Tests/ViewElementTest.php
@@ -71,7 +71,7 @@ public function testViewElement() {
     // Test a form.
     $this->drupalGet('views_test_data_element_form');
 
-    $xpath = $this->xpath('//div[@class="views-element-container form-wrapper"]');
+    $xpath = $this->xpath('//div[@class="views-element-container js-form-wrapper form-wrapper"]');
     $this->assertTrue($xpath, 'The view container has been found on the form.');
 
     $xpath = $this->xpath('//div[@class="view-content"]');
@@ -138,7 +138,7 @@ public function testViewElementEmbed() {
     // Test a form.
     $this->drupalGet('views_test_data_element_embed_form');
 
-    $xpath = $this->xpath('//div[@class="views-element-container form-wrapper"]');
+    $xpath = $this->xpath('//div[@class="views-element-container js-form-wrapper form-wrapper"]');
     $this->assertTrue($xpath, 'The view container has been found on the form.');
 
     $xpath = $this->xpath('//div[@class="view-content"]');
diff --git a/core/themes/classy/templates/form/container.html.twig b/core/themes/classy/templates/form/container.html.twig
index 6fb8159..167965c 100644
--- a/core/themes/classy/templates/form/container.html.twig
+++ b/core/themes/classy/templates/form/container.html.twig
@@ -17,4 +17,10 @@
  * @ingroup themeable
  */
 #}
-<div{{ attributes.addClass(has_parent ? 'form-wrapper') }}>{{ children }}</div>
+{%
+  set classes = [
+    has_parent ? 'js-form-wrapper',
+    has_parent ? 'form-wrapper',
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>{{ children }}</div>
diff --git a/core/themes/classy/templates/form/datetime-wrapper.html.twig b/core/themes/classy/templates/form/datetime-wrapper.html.twig
index 45ba069..fbf6bb2 100644
--- a/core/themes/classy/templates/form/datetime-wrapper.html.twig
+++ b/core/themes/classy/templates/form/datetime-wrapper.html.twig
@@ -18,6 +18,7 @@
 {%
   set title_classes = [
     'label',
+    required ? 'js-form-required',
     required ? 'form-required',
   ]
 %}
diff --git a/core/themes/classy/templates/form/fieldset.html.twig b/core/themes/classy/templates/form/fieldset.html.twig
index ab6796c..65533ec 100644
--- a/core/themes/classy/templates/form/fieldset.html.twig
+++ b/core/themes/classy/templates/form/fieldset.html.twig
@@ -21,10 +21,19 @@
  * @ingroup themeable
  */
 #}
-<fieldset{{ attributes.addClass('form-item', 'form-wrapper') }}>
+{%
+  set classes = [
+    'js-form-item',
+    'form-item',
+    'js-form-wrapper',
+    'form-wrapper',
+  ]
+%}
+<fieldset{{ attributes.addClass(classes) }}>
   {%
     set legend_span_classes = [
       'fieldset-legend',
+      required ? 'js-form-required',
       required ? 'form-required',
     ]
   %}
diff --git a/core/themes/classy/templates/form/form-element-label.html.twig b/core/themes/classy/templates/form/form-element-label.html.twig
index 6ececd9..7696609 100644
--- a/core/themes/classy/templates/form/form-element-label.html.twig
+++ b/core/themes/classy/templates/form/form-element-label.html.twig
@@ -18,6 +18,7 @@
   set classes = [
     title_display == 'after' ? 'option',
     title_display == 'invisible' ? 'visually-hidden',
+    required ? 'js-form-required',
     required ? 'form-required',
   ]
 %}
