diff --git a/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
index 7b166f8..f97fa9c 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/JavascriptStatesForm.php
@@ -76,6 +76,15 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         ],
       ],
     ];
+    $form['textfield_required_when_checkbox_trigger_checked'] = [
+      '#type' => 'textfield',
+      '#title' => 'Texfield required when checkbox trigger checked',
+      '#states' => [
+        'required' => [
+          ':input[name="checkbox_trigger"]' => ['checked' => TRUE],
+        ],
+      ],
+    ];
     $form['checkbox_unchecked_when_textfield_trigger_filled'] = [
       '#type' => 'checkbox',
       '#title' => 'Checkbox unchecked when textfield trigger filled',
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
index 7d686ae..83fb9b8 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
@@ -33,6 +33,8 @@ public function testCheckboxTriggeredElements() {
     // Test that the details element is collapsed so the textfield inside is not
     // visible.
     $this->assertFieldNotVisible('textfield_in_details');
+    // Test that the textfield is optional.
+    $this->assertFieldOptional('textfield_required_when_checkbox_trigger_checked');
 
     // Change state: check the checkbox.
     $trigger->check();
@@ -42,6 +44,8 @@ public function testCheckboxTriggeredElements() {
     // Test that the details element is now open so the textfield inside is now
     // visible.
     $this->assertFieldVisible('textfield_in_details');
+    // Test that the textfield is now required.
+    $this->assertFieldRequired('textfield_required_when_checkbox_trigger_checked');
 
     // Change back to the initial state to avoid issues running the next tests.
     $trigger->uncheck();
@@ -268,4 +272,34 @@ public function assertFieldNotVisible($locator, TraversableElement $container =
     $this->assertSession()->assertElementNotVisible('named', ['field', $locator], $container);
   }
 
+  /**
+   * Asserts that the given field is required.
+   *
+   * @param string $locator
+   *   One of id|name|label|value for the field.
+   * @param \Behat\Mink\Element\TraversableElement $container
+   *   (optional) The document to check against. Defaults to the current page.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   *   When the element doesn't exist.
+   */
+  public function assertFieldRequired($locator, TraversableElement $container = NULL) {
+    $this->assertSession()->assertElementRequired('named', ['field', $locator], $container);
+  }
+
+  /**
+   * Asserts that the given field is optional (not required).
+   *
+   * @param string $locator
+   *   One of id|name|label|value for the field.
+   * @param \Behat\Mink\Element\TraversableElement $container
+   *   (optional) The document to check against. Defaults to the current page.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   *   When the element doesn't exist.
+   */
+  public function assertFieldOptional($locator, TraversableElement $container = NULL) {
+    $this->assertSession()->assertElementOptional('named', ['field', $locator], $container);
+  }
+
 }
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
index a37bfbc..90043e4 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/JSWebAssert.php
@@ -61,14 +61,8 @@ function isAjaxing(instance) {
    *   When the element doesn't exist.
    */
   public function assertElementVisible($selector_type, $selector, ElementInterface $container = NULL) {
-    $container = $container ?: $this->session->getPage();
-    $node = $container->find($selector_type, $selector);
-    if ($node === NULL) {
-      if (is_array($selector)) {
-        $selector = implode(' ', $selector);
-      }
-      throw new ElementNotFoundException($this->session->getDriver(), 'element', $selector_type, $selector);
-    }
+    $node = $this->findNode($selector_type, $selector, $container);
+
     $message = sprintf(
       'Element "%s" is not visible.',
       $this->getMatchingElementRepresentation($selector_type, $selector)
@@ -90,14 +84,8 @@ public function assertElementVisible($selector_type, $selector, ElementInterface
    *   When the element doesn't exist.
    */
   public function assertElementNotVisible($selector_type, $selector, ElementInterface $container = NULL) {
-    $container = $container ?: $this->session->getPage();
-    $node = $container->find($selector_type, $selector);
-    if ($node === NULL) {
-      if (is_array($selector)) {
-        $selector = implode(' ', $selector);
-      }
-      throw new ElementNotFoundException($this->session->getDriver(), 'element', $selector_type, $selector);
-    }
+    $node = $this->findNode($selector_type, $selector, $container);
+
     $message = sprintf(
       'Element "%s" is not visible.',
       $this->getMatchingElementRepresentation($selector_type, $selector)
@@ -106,6 +94,52 @@ public function assertElementNotVisible($selector_type, $selector, ElementInterf
   }
 
   /**
+   * Asserts that the specific element is not required on the current page.
+   *
+   * @param string $selector_type
+   *   The element selector type (css, xpath).
+   * @param string|array $selector
+   *   The element selector.
+   * @param \Behat\Mink\Element\ElementInterface $container
+   *   The document to check against.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   *   When the element doesn't exist.
+   */
+  public function assertElementRequired($selector_type, $selector, ElementInterface $container = NULL) {
+    $node = $this->findNode($selector_type, $selector, $container);
+
+    $message = sprintf(
+      'Element "%s" is required.',
+      $this->getMatchingElementRepresentation($selector_type, $selector)
+    );
+    $this->assertElement($node->getAttribute('required') == 'required', $message, $node);
+  }
+
+  /**
+   * Asserts that the specific element is not required on the current page.
+   *
+   * @param string $selector_type
+   *   The element selector type (css, xpath).
+   * @param string|array $selector
+   *   The element selector.
+   * @param \Behat\Mink\Element\ElementInterface $container
+   *   The document to check against.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   *   When the element doesn't exist.
+   */
+  public function assertElementOptional($selector_type, $selector, ElementInterface $container = NULL) {
+    $node = $this->findNode($selector_type, $selector, $container);
+
+    $message = sprintf(
+      'Element "%s" is optional.',
+      $this->getMatchingElementRepresentation($selector_type, $selector)
+    );
+    $this->assertElement(!$node->hasAttribute('required'), $message, $node);
+  }
+
+  /**
    * {@inheritdoc}
    */
   protected function assertElement($condition, $message, Element $element) {
@@ -117,6 +151,35 @@ protected function assertElement($condition, $message, Element $element) {
   }
 
   /**
+   * Find a node in the container specified usually the current page.
+   *
+   * @param string $selector_type
+   *   The element selector type (CSS, XPath).
+   * @param string $selector
+   *   The selector engine name. See ElementInterface::findAll() for the
+   *   supported selectors.
+   * @param \Behat\Mink\Element\ElementInterface $container
+   *   The document to check against.
+   *
+   * @return \Behat\Mink\Element\ElementInterface $node
+   *   The node element if exists in the current container.
+   *
+   * @throws \Behat\Mink\Exception\ElementNotFoundException
+   *   When the element doesn't exist.
+   */
+  protected function findNode($selector_type, $selector, ElementInterface $container = NULL) {
+    $container = $container ?: $this->session->getPage();
+    $node = $container->find($selector_type, $selector);
+    if ($node === NULL) {
+      if (is_array($selector)) {
+        $selector = implode(' ', $selector);
+      }
+      throw new ElementNotFoundException($this->session->getDriver(), 'element', $selector_type, $selector);
+    }
+    return $node;
+  }
+
+  /**
    * {@inheritdoc}
    */
   protected function getMatchingElementRepresentation($selector_type, $selector, $plural = FALSE) {
