diff --git a/js/webform.element.other.js b/js/webform.element.other.js
index f6c500d6..62d81fff 100644
--- a/js/webform.element.other.js
+++ b/js/webform.element.other.js
@@ -14,14 +14,19 @@
    *   TRUE will display the text field. FALSE with hide and clear the text field.
    * @param {object} $element
    *   The input (text) field to be toggled.
+   * @param {string} effect
+   *   Effect.
    */
-  function toggleOther(show, $element) {
+  function toggleOther(show, $element, effect) {
     var $input = $element.find('input');
+    var hideEffect = (effect === false) ? 'hide' : 'slideUp';
+    var showEffect = (effect === false) ? 'show' : 'slideDown';
+
     if (show) {
       // Limit the other inputs width to the parent's container.
       $element.width($element.parent().width());
       // Display the element.
-      $element.slideDown();
+      $element[showEffect]();
       // Focus and require the input.
       $input.focus().prop('required', true);
       // Restore the input's value.
@@ -36,7 +41,8 @@
       });
     }
     else {
-      $element.slideUp();
+      // Hide the element.
+      $element[hideEffect]();
       // Save the input's value.
       $input.data('webform-value', $input.val());
       // Empty and un-required the input.
@@ -58,13 +64,11 @@
         var $otherOption = $element.find('option[value="_other_"]');
         var $input = $element.find('.js-webform-select-other-input');
 
-        if ($otherOption.is(':selected')) {
-          $input.show().find('input').prop('required', true);
-        }
-
         $select.on('change', function () {
           toggleOther($otherOption.is(':selected'), $input);
         });
+
+        toggleOther($otherOption.is(':selected'), $input, false);
       });
     }
   };
@@ -81,13 +85,11 @@
         var $checkbox = $element.find('input[value="_other_"]');
         var $input = $element.find('.js-webform-checkboxes-other-input');
 
-        if ($checkbox.is(':checked')) {
-          $input.show().find('input').prop('required', true);
-        }
-
         $checkbox.on('change', function () {
           toggleOther(this.checked, $input);
         });
+
+        toggleOther($checkbox.is(':checked'), $input, false);
       });
     }
   };
@@ -105,13 +107,11 @@
         var $radios = $element.find('input[type="radio"]');
         var $input = $element.find('.js-webform-radios-other-input');
 
-        if ($radios.filter(':checked').val() === '_other_') {
-          $input.show().find('input').prop('required', true);
-        }
-
         $radios.on('change', function () {
           toggleOther(($radios.filter(':checked').val() === '_other_'), $input);
         });
+
+        toggleOther(($radios.filter(':checked').val() === '_other_'), $input, false);
       });
     }
   };
@@ -129,10 +129,6 @@
         var $buttons = $element.find('input[type="radio"]');
         var $input = $element.find('.js-webform-buttons-other-input');
 
-        if ($buttons.filter(':checked').val() === '_other_') {
-          $input.show().find('input').prop('required', true);
-        }
-
         // Note: Initializing buttonset here so that we can set the onchange
         // event handler.
         // @see Drupal.behaviors.webformButtons
@@ -150,6 +146,8 @@
         $container.on('webform:disabled', function () {
           $container.buttonset('option', 'disabled', $container.find('input[type="radio"]:disabled').length);
         });
+
+        toggleOther(($buttons.filter(':checked').val() === '_other_'), $input, false);
       });
     }
   };
diff --git a/js/webform.states.js b/js/webform.states.js
index d3a3f793..844b98aa 100644
--- a/js/webform.states.js
+++ b/js/webform.states.js
@@ -7,8 +7,9 @@
 
   'use strict';
 
-  // Issue #2860529: Conditional required File upload field don't work.
   var $document = $(document);
+
+  // Issue #2860529: Conditional required File upload field don't work.
   $document.on('state:required', function (e) {
     if (e.trigger) {
       if (e.value) {
@@ -20,38 +21,38 @@
     }
   });
 
-  // Make absolutely sure the below event handlers are triggered after
-  // the /core/misc/states.js event handlers by attaching them after DOM load.
-  $(function () {
-    var $document = $(document);
-    $document.on('state:visible', function (e) {
-      if (!e.trigger) {
-        return true;
-      }
-
-      if (!e.value) {
-        // @see https://www.sitepoint.com/jquery-function-clear-form-data/
+  $document.on('state:visible', function (e) {
+    if (e.trigger) {
+      if (e.value) {
         $(':input', e.target).andSelf().each(function () {
-          backupValueAndRequired(this);
-          clearValueAndRequired(this);
+          restoreValueAndRequired(this);
           triggerEventHandlers(this);
         });
       }
       else {
+        // @see https://www.sitepoint.com/jquery-function-clear-form-data/
         $(':input', e.target).andSelf().each(function () {
-          restoreValueAndRequired(this);
+          backupValueAndRequired(this);
+          clearValueAndRequired(this);
           triggerEventHandlers(this);
         });
       }
-    });
-
-    $document.on('state:disabled', function (e) {
-      if (e.trigger) {
-        $(e.target).trigger('webform:disabled')
-          .find('select, input, textarea').trigger('webform:disabled');
-      }
-    });
+    }
+  });
 
+  $document.on('state:disabled', function (e) {
+    if (e.trigger) {
+      // Make sure disabled property is set before triggering webform:disabled.
+      // Copied from: core/misc/states.js
+      $(e.target)
+        .prop('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);
+
+      // Trigger webform:disabled.
+      $(e.target).trigger('webform:disabled')
+        .find('select, input, textarea').trigger('webform:disabled');
+    }
   });
 
   /**
@@ -114,7 +115,6 @@
     else if (type != 'submit' && type != 'button') {
       $input.data('webform-value', input.value);
     }
-
   }
 
   /**
diff --git a/src/Element/WebformComputedBase.php b/src/Element/WebformComputedBase.php
index ef3d2648..bec37420 100644
--- a/src/Element/WebformComputedBase.php
+++ b/src/Element/WebformComputedBase.php
@@ -86,6 +86,11 @@ abstract class WebformComputedBase extends FormElement {
       // @see drupal_process_states;
       $element['#type'] = 'item';
     }
+
+    if (isset($element['#states'])) {
+      webform_process_states($element, '#wrapper_attributes');
+    }
+
     return $element;
   }
 
diff --git a/src/Element/WebformMapping.php b/src/Element/WebformMapping.php
index fdbf8f91..f1927c31 100644
--- a/src/Element/WebformMapping.php
+++ b/src/Element/WebformMapping.php
@@ -124,6 +124,10 @@ class WebformMapping extends FormElement {
 
     $element['#element_validate'] = [[get_called_class(), 'validateWebformMapping']];
 
+    if (isset($element['#states'])) {
+      webform_process_states($element, '#wrapper_attributes');
+    }
+
     return $element;
   }
 
