diff --git a/core/misc/states.js b/core/misc/states.js
index a55c4d08db00e8b36c6d5d7b67029acab791448e..3109e1f1bdb0b02437c6c429cfdc3657e40dec53 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -149,6 +149,7 @@
    *
    * @prop {function} RegExp
    * @prop {function} Function
+   * @prop {function} Array
    * @prop {function} Number
    */
   states.Dependent.comparisons = {
@@ -159,6 +160,15 @@
       // The "reference" variable is a comparison function.
       return reference(value);
     },
+    Array(reference, value) {
+      // Make sure value is an array.
+      if (!Array.isArray(value)) {
+        return false;
+      }
+
+      // The arrays values should match.
+      return JSON.stringify(reference.sort()) === JSON.stringify(value.sort());
+    },
     Number(reference, value) {
       // If "reference" is a number and "value" is a string, then cast
       // reference as a string before applying the strict comparison in
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 bf367003d1050fb243b8149ca0ede1b708328ae8..0677df3bd06e3a2be32510d7208f670e6cba5ab7 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
@@ -24,6 +24,12 @@ public function getFormId() {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
+
+    $form['header_triggers'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h2',
+      '#value' => 'Triggers',
+    ];
     $form['checkbox_trigger'] = [
       '#type' => 'checkbox',
       '#title' => 'Checkbox trigger',
@@ -112,8 +118,30 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       '#title' => 'Number trigger',
     ];
 
+    $form['multiple_select_trigger'] = [
+      '#type' => 'select',
+      '#multiple' => TRUE,
+      '#title' => 'Multiple select trigger',
+      '#options' => [
+        'value1' => 'Value 1',
+        'value2' => 'Value 2',
+        'value3' => 'Value 3',
+      ],
+    ];
+
     // Tested fields.
+    $form['header_tested_elements'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h2',
+      '#value' => 'Tested elements',
+    ];
+
     // Checkbox trigger.
+    $form['header_checkbox'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Checkbox tests',
+    ];
     $form['textfield_invisible_when_checkbox_trigger_checked'] = [
       '#type' => 'textfield',
       '#title' => 'Textfield invisible when checkbox trigger checked',
@@ -318,6 +346,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Checkboxes trigger.
+    $form['header_checkboxes'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Checkboxes tests',
+    ];
     $form['textfield_visible_when_checkboxes_trigger_value2_checked'] = [
       '#type' => 'textfield',
       '#title' => 'Textfield visible when checkboxes trigger value2 checked',
@@ -338,6 +371,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Radios trigger.
+    $form['header_radios'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Radios tests',
+    ];
     $form['fieldset_visible_when_radios_trigger_has_value2'] = [
       '#type' => 'fieldset',
       '#title' => 'Fieldset visible when radio trigger has value2',
@@ -407,6 +445,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Select trigger
+    $form['header_select'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Select tests',
+    ];
     $form['item_visible_when_select_trigger_has_value2'] = [
       '#type' => 'item',
       '#title' => 'Item visible when select trigger has value2',
@@ -438,7 +481,72 @@ public function buildForm(array $form, FormStateInterface $form_state) {
       ],
     ];
 
+    // Multiple select trigger.
+    $form['header_multiple_select'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Multiple select tests',
+    ];
+    $form['item_visible_when_multiple_select_trigger_has_value2'] = [
+      '#type' => 'item',
+      '#title' => 'Item visible when multiple select trigger has value2',
+      '#states' => [
+        'visible' => [
+          'select[name="multiple_select_trigger[]"]' => ['value' => ['value2']],
+        ],
+      ],
+    ];
+    $form['item_visible_when_multiple_select_trigger_has_no_value'] = [
+      '#type' => 'item',
+      '#title' => 'Item visible when multiple select trigger has no value',
+      '#states' => [
+        'visible' => [
+          'select[name="multiple_select_trigger[]"]' => ['value' => []],
+        ],
+      ],
+    ];
+    $form['textfield_visible_when_multiple_select_trigger_has_value3'] = [
+      '#type' => 'textfield',
+      '#title' => 'Textfield visible when multiple select trigger has value3',
+      '#states' => [
+        'visible' => [
+          'select[name="multiple_select_trigger[]"]' => ['value' => ['value3']],
+        ],
+      ],
+    ];
+    $form['textfield_visible_when_multiple_select_trigger_has_value2_or_value3'] = [
+      '#type' => 'textfield',
+      '#title' => 'Textfield visible when multiple select trigger has value2 OR value3',
+      '#states' => [
+        'visible' => [
+          'select[name="multiple_select_trigger[]"]' => [
+            ['value' => ['value2']],
+            ['value' => ['value3']],
+          ],
+        ],
+      ],
+    ];
+    $form['textfield_visible_when_multiple_select_trigger_has_value2_and_value3'] = [
+      '#type' => 'textfield',
+      '#title' => 'Textfield visible when multiple select trigger has value2 AND value3',
+      '#states' => [
+        'visible' => [
+          'select[name="multiple_select_trigger[]"]' => [
+            'value' => [
+              'value3',
+              'value2',
+            ],
+          ],
+        ],
+      ],
+    ];
+
     // Textfield trigger.
+    $form['header_textfield'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Textfield tests',
+    ];
     $form['checkbox_checked_when_textfield_trigger_filled'] = [
       '#type' => 'checkbox',
       '#title' => 'Checkbox checked when textfield trigger filled',
@@ -503,6 +611,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Multiple triggers.
+    $form['header_multiple_triggers'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Multiple triggers tests',
+    ];
     $form['item_visible_when_select_trigger_has_value2_and_textfield_trigger_filled'] = [
       '#type' => 'item',
       '#title' => 'Item visible when select trigger has value2 and textfield trigger filled',
@@ -515,6 +628,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
     ];
 
     // Number triggers.
+    $form['header_number'] = [
+      '#type' => 'html_tag',
+      '#tag' => 'h3',
+      '#value' => 'Number tests',
+    ];
     $form['item_visible_when_number_trigger_filled_by_spinner'] = [
       '#type' => 'item',
       '#title' => 'Item visible when number trigger filled by spinner widget',
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
index 83941319792e7c2f67b62757eb8678a5852f0a7e..b5c0d9178906e38fc19aa3f067d3c9d6ae4325f7 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/Core/Form/JavascriptStatesTest.php
@@ -69,6 +69,7 @@ public function testJavascriptStates() {
     $this->doTextfieldTriggerTests();
     $this->doRadiosTriggerTests();
     $this->doSelectTriggerTests();
+    $this->doMultipleSelectTriggerTests();
     $this->doMultipleTriggerTests();
     $this->doNestedTriggerTests();
     $this->doElementsDisabledStateTests();
@@ -444,6 +445,63 @@ protected function doSelectTriggerTests() {
     $this->assertTrue($textfield_visible_value2_or_value3->isVisible());
   }
 
+  /**
+   * Tests states of elements triggered by a multiple select element.
+   */
+  protected function doMultipleSelectTriggerTests() {
+    $this->drupalGet('form-test/javascript-states-form');
+    $page = $this->getSession()->getPage();
+    // Find trigger and target elements.
+    $trigger = $page->findField('multiple_select_trigger[]');
+    $this->assertNotEmpty($trigger);
+    $item_visible_value2 = $this->assertSession()->elementExists('css', '#edit-item-visible-when-multiple-select-trigger-has-value2');
+    $item_visible_no_value = $this->assertSession()->elementExists('css', '#edit-item-visible-when-multiple-select-trigger-has-no-value');
+    $textfield_visible_value3 = $page->findField('textfield_visible_when_multiple_select_trigger_has_value3');
+    $this->assertNotEmpty($textfield_visible_value3);
+    $textfield_visible_value2_or_value3 = $page->findField('textfield_visible_when_multiple_select_trigger_has_value2_or_value3');
+    $this->assertNotEmpty($textfield_visible_value2_or_value3);
+    $textfield_visible_value2_and_value3 = $page->findField('textfield_visible_when_multiple_select_trigger_has_value2_and_value3');
+    $this->assertNotEmpty($textfield_visible_value2_and_value3);
+
+    // Verify initial state.
+    $this->assertFalse($item_visible_value2->isVisible());
+    $this->assertTrue($item_visible_no_value->isVisible());
+    $this->assertFalse($textfield_visible_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_or_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_and_value3->isVisible());
+    // Change state: select the 'Value 2' option.
+    $trigger->setValue('value2');
+    $this->assertTrue($item_visible_value2->isVisible());
+    $this->assertFalse($item_visible_no_value->isVisible());
+    $this->assertFalse($textfield_visible_value3->isVisible());
+    $this->assertTrue($textfield_visible_value2_or_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_and_value3->isVisible());
+    // Change state: select the 'Value 3' option.
+    $trigger->setValue('value3');
+    $this->assertFalse($item_visible_value2->isVisible());
+    $this->assertFalse($item_visible_no_value->isVisible());
+    $this->assertTrue($textfield_visible_value3->isVisible());
+    $this->assertTrue($textfield_visible_value2_or_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_and_value3->isVisible());
+    // Change state: select 'Value2' and 'Value 3' options.
+    $trigger->setValue(['value2', 'value3']);
+    $this->assertFalse($item_visible_value2->isVisible());
+    $this->assertFalse($item_visible_no_value->isVisible());
+    $this->assertFalse($textfield_visible_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_or_value3->isVisible());
+    $this->assertTrue($textfield_visible_value2_and_value3->isVisible());
+    // Restore initial trigger state (clear the values).
+    $trigger->setValue([]);
+    // Make sure the initial element states are restored.
+    $this->assertFalse($item_visible_value2->isVisible());
+    $this->assertFalse($textfield_visible_value3->isVisible());
+    $this->assertFalse($textfield_visible_value2_or_value3->isVisible());
+    // @todo These last two look to be correct, but the assertion is failing.
+    // @see https://www.drupal.org/project/drupal/issues/3367310
+    // $this->assertTrue($item_visible_no_value->isVisible());
+    // $this->assertFalse($textfield_visible_value2_and_value3->isVisible());
+  }
+
   /**
    * Tests states of elements triggered by multiple elements.
    */