From 8f9e0bd08350b2140a6de96d6cada9cbcabfa2bc Mon Sep 17 00:00:00 2001
From: Lauri Eskola <lauri.eskola@acquia.com>
Date: Mon, 24 Apr 2023 09:58:55 +0300
Subject: [PATCH] Issue #2911932 by bnjmnm, arnaud-brugnon, EthanT,
 leslie.cordell, smustgrave, nod_: Correct vertical tab does not focus on form
 validation

---
 core/misc/vertical-tabs.js                    | 15 ++++++++++
 core/modules/ckeditor5/js/ckeditor5.admin.js  | 17 -----------
 .../Form/FormTestGroupVerticalTabsForm.php    | 13 +++++++++
 .../Core/Form/FormGroupingElementsTest.php    | 29 +++++++++++++++++++
 4 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js
index 85f200f5f809..67a9b3ea4de0 100644
--- a/core/misc/vertical-tabs.js
+++ b/core/misc/vertical-tabs.js
@@ -118,6 +118,21 @@
           }
         },
       );
+
+      // If a validation error is within a vertical tab, open that tab.
+      context.querySelectorAll('details .form-item .error').forEach((item) => {
+        const details = item.closest('details');
+
+        if (details.style.display === 'none') {
+          const tabSelect = document.querySelector(
+            "[href='#".concat(details.id, "']"),
+          );
+
+          if (tabSelect) {
+            tabSelect.click();
+          }
+        }
+      });
     },
   };
 
diff --git a/core/modules/ckeditor5/js/ckeditor5.admin.js b/core/modules/ckeditor5/js/ckeditor5.admin.js
index 0e3d3487eb8e..0cb64ee2f5f5 100644
--- a/core/modules/ckeditor5/js/ckeditor5.admin.js
+++ b/core/modules/ckeditor5/js/ckeditor5.admin.js
@@ -1057,21 +1057,4 @@
     // Call the original behavior.
     originalFilterStatusAttach(context, settings);
   };
-
-  // Activates otherwise-inactive tabs that have form elements with validation
-  // errors.
-  // @todo Remove when https://www.drupal.org/project/drupal/issues/2911932 lands.
-  Drupal.behaviors.tabErrorsVisible = {
-    attach(context) {
-      context.querySelectorAll('details .form-item .error').forEach((item) => {
-        const details = item.closest('details');
-        if (details.style.display === 'none') {
-          const tabSelect = document.querySelector(`[href='#${details.id}']`);
-          if (tabSelect) {
-            tabSelect.click();
-          }
-        }
-      });
-    },
-  };
 })(Drupal, drupalSettings, jQuery, JSON, once, Sortable, tabbable);
diff --git a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
index 7a29d7d7ee00..3e47c908c8c1 100644
--- a/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
+++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestGroupVerticalTabsForm.php
@@ -44,9 +44,22 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#type' => 'textfield',
       '#title' => 'Second nested element in details element',
     ];
+    $form['submit'] = [
+      '#type' => 'submit',
+      '#value' => 'Save',
+    ];
     return $form;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {
+    if ($form_state->getValue('element_2') === 'bad') {
+      $form_state->setErrorByName('element_2', $this->t('there was an error'));
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php
index e4cfcb9bec23..488e07d20a72 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/FormGroupingElementsTest.php
@@ -135,4 +135,33 @@ public function testDetailsChildVisibility() {
     $this->assertEquals('true', $summary->getAttribute('aria-pressed'));
   }
 
+  /**
+   * Confirms tabs containing a field with a validation error are open.
+   */
+  public function testVerticalTabValidationVisibility() {
+    $page = $this->getSession()->getPage();
+    $assert_session = $this->assertSession();
+
+    $this->drupalGet('form-test/group-vertical-tabs');
+    $page->clickLink('Second group element');
+    $input_field = $assert_session->waitForField('element_2');
+    $this->assertNotNull($input_field);
+
+    // Enter a value that will trigger a validation error.
+    $input_field->setValue('bad');
+
+    // Switch to a tab that does not have the error-causing field.
+    $page->clickLink('First group element');
+    $this->assertNotNull($assert_session->waitForElementVisible('css', '#edit-meta'));
+
+    // Submit the form.
+    $page->pressButton('Save');
+
+    // Confirm there is an error.
+    $assert_session->waitForText('there was an error');
+
+    // Confirm the tab containing the field with error is open.
+    $this->assertNotNull($assert_session->waitForElementVisible('css', '[name="element_2"].error'));
+  }
+
 }
-- 
GitLab