diff --git a/ee/app/assets/javascripts/work_items/components/work_item_weight_with_edit.vue b/ee/app/assets/javascripts/work_items/components/work_item_weight_with_edit.vue
index 9f532e1b92f85fbecf33cad5d8a88c2f81e362b0..6ccdb4c7a997239d71594c53152fae0504397952 100644
--- a/ee/app/assets/javascripts/work_items/components/work_item_weight_with_edit.vue
+++ b/ee/app/assets/javascripts/work_items/components/work_item_weight_with_edit.vue
@@ -1,5 +1,5 @@
 <script>
-import { GlButton, GlForm, GlFormInput, GlTooltipDirective } from '@gitlab/ui';
+import { GlButton, GlForm, GlFormInput, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
 import * as Sentry from '~/sentry/sentry_browser_wrapper';
 import Tracking from '~/tracking';
 import {
@@ -18,6 +18,7 @@ export default {
     GlButton,
     GlForm,
     GlFormInput,
+    GlLoadingIcon,
   },
   mixins: [Tracking.mixin()],
   inject: ['hasIssueWeightsFeature'],
@@ -50,12 +51,16 @@ export default {
       isEditing: false,
       clickingClearButton: false,
       workItem: {},
+      isUpdating: false,
     };
   },
   computed: {
     hasWeight() {
       return this.weight !== null;
     },
+    showRemoveWeight() {
+      return this.hasWeight && !this.isUpdating;
+    },
     tracking() {
       return {
         category: TRACKING_CATEGORY_SHOW,
@@ -83,9 +88,13 @@ export default {
     updateWeight(weight) {
       if (this.clickingClearButton) return;
       if (!this.canUpdate) return;
-      this.isEditing = false;
 
-      if (this.weight === weight) return;
+      if (this.weight === weight) {
+        this.isEditing = false;
+        return;
+      }
+
+      this.isUpdating = true;
 
       this.track('updated_weight');
       this.$apollo
@@ -109,6 +118,10 @@ export default {
           const msg = sprintfWorkItem(I18N_WORK_ITEM_ERROR_UPDATING, this.workItemType);
           this.$emit('error', msg);
           Sentry.captureException(error);
+        })
+        .finally(() => {
+          this.isUpdating = false;
+          this.isEditing = false;
         });
     },
   },
@@ -132,12 +145,15 @@ export default {
       >
     </div>
     <gl-form v-if="isEditing" @submit.prevent="blurInput">
-      <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+      <div class="gl-display-flex gl-align-items-center">
         <label :for="$options.inputId" class="gl-mb-0">{{ __('Weight') }}</label>
+        <gl-loading-icon v-if="isUpdating" size="sm" inline class="gl-ml-3" />
         <gl-button
           data-testid="apply-weight"
           category="tertiary"
           size="small"
+          class="gl-ml-auto"
+          :disabled="isUpdating"
           @click="isEditing = false"
           >{{ __('Apply') }}</gl-button
         >
@@ -150,6 +166,7 @@ export default {
           min="0"
           class="hide-unfocused-input-decoration gl-display-block"
           type="number"
+          :disabled="isUpdating"
           :placeholder="__('Enter a number')"
           :value="weight"
           autofocus
@@ -158,7 +175,7 @@ export default {
           @keydown.exact.esc.stop="blurInput"
         />
         <gl-button
-          v-if="hasWeight"
+          v-if="showRemoveWeight"
           v-gl-tooltip
           data-testid="remove-weight"
           variant="default"
diff --git a/ee/spec/frontend/work_items/components/work_item_weight_with_edit_spec.js b/ee/spec/frontend/work_items/components/work_item_weight_with_edit_spec.js
index ca506ae6d78b640dc23a2c2ceb713d21c4d778b4..d8f61957bbd7234f244f4c94a2882549f4be70e4 100644
--- a/ee/spec/frontend/work_items/components/work_item_weight_with_edit_spec.js
+++ b/ee/spec/frontend/work_items/components/work_item_weight_with_edit_spec.js
@@ -1,4 +1,4 @@
-import { GlForm, GlFormInput } from '@gitlab/ui';
+import { GlForm, GlFormInput, GlLoadingIcon } from '@gitlab/ui';
 import Vue, { nextTick } from 'vue';
 import VueApollo from 'vue-apollo';
 import WorkItemWeight from 'ee/work_items/components/work_item_weight_with_edit.vue';
@@ -25,6 +25,7 @@ describe('WorkItemWeight component', () => {
   const findLabel = () => wrapper.find('label');
   const findForm = () => wrapper.findComponent(GlForm);
   const findInput = () => wrapper.findComponent(GlFormInput);
+  const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
   const findClearButton = () => wrapper.find('[data-testid="remove-weight"]');
 
   const createComponent = ({
@@ -80,6 +81,27 @@ describe('WorkItemWeight component', () => {
       expect(findLabel().exists()).toBe(true);
       expect(findHeader().classes('gl-sr-only')).toBe(true);
     });
+
+    it('shows loading spinner while updating', async () => {
+      createComponent({
+        isEditing: true,
+        weight: 0,
+        canUpdate: true,
+      });
+
+      await nextTick();
+
+      findInput().setValue('1');
+      findInput().trigger('blur');
+
+      await nextTick();
+
+      expect(findLoadingIcon().exists()).toBe(true);
+
+      await waitForPromises();
+
+      expect(findLoadingIcon().exists()).toBe(false);
+    });
   });
 
   describe('edit button', () => {
@@ -212,6 +234,27 @@ describe('WorkItemWeight component', () => {
       });
     });
 
+    it('is disabled while updating, and removed after', async () => {
+      createComponent({
+        isEditing: true,
+        weight: 0,
+        canUpdate: true,
+      });
+
+      await nextTick();
+
+      findInput().setValue('1');
+      findInput().trigger('blur');
+
+      await nextTick();
+
+      expect(findInput().attributes('disabled')).toBe('disabled');
+
+      await waitForPromises();
+
+      expect(findInput().exists()).toBe(false);
+    });
+
     it('does not call a mutation to update the weight when the input value is the same', async () => {
       const mutationSpy = jest.fn().mockResolvedValue(updateWorkItemMutationResponse);
       createComponent({ isEditing: true, mutationHandler: mutationSpy, canUpdate: true });