diff --git a/app/assets/javascripts/work_items/components/item_state.vue b/app/assets/javascripts/work_items/components/item_state.vue
deleted file mode 100644
index 2100cc67c8c0e28117118888e9afa0f2a82371dc..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/work_items/components/item_state.vue
+++ /dev/null
@@ -1,71 +0,0 @@
-<script>
-import { GlFormGroup, GlFormSelect } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { STATE_OPEN, STATE_CLOSED } from '../constants';
-
-export default {
-  i18n: {
-    status: __('Status'),
-  },
-  states: [
-    {
-      value: STATE_OPEN,
-      text: __('Open'),
-    },
-    {
-      value: STATE_CLOSED,
-      text: __('Closed'),
-    },
-  ],
-  components: {
-    GlFormGroup,
-    GlFormSelect,
-  },
-  props: {
-    state: {
-      type: String,
-      required: true,
-    },
-    disabled: {
-      type: Boolean,
-      required: false,
-      default: false,
-    },
-  },
-  computed: {
-    currentState() {
-      return this.$options.states[this.state];
-    },
-  },
-  methods: {
-    setState(newState) {
-      if (newState !== this.state) {
-        this.$emit('changed', newState);
-      }
-    },
-  },
-  labelId: 'work-item-state-select',
-};
-</script>
-
-<template>
-  <gl-form-group
-    :label="$options.i18n.status"
-    :label-for="$options.labelId"
-    label-cols="3"
-    label-cols-lg="2"
-    label-class="gl-pb-0! gl-overflow-wrap-break work-item-field-label"
-    class="gl-align-items-center"
-  >
-    <gl-form-select
-      :id="$options.labelId"
-      :value="state"
-      :options="$options.states"
-      :disabled="disabled"
-      data-testid="work-item-state-select"
-      class="hide-unfocused-input-decoration work-item-field-value gl-w-auto gl-pl-4 gl-my-1"
-      :class="{ 'gl-bg-transparent! gl-cursor-text!': disabled }"
-      @change="setState"
-    />
-  </gl-form-group>
-</template>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
index c330eccb1868c1f6fe99381b8f1c27d314929e94..66ad3d50287728386564a5c330eb4d38d8b8183f 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
@@ -265,6 +265,7 @@ export default {
             :comment-button-text="commentButtonText"
             @submitForm="updateWorkItem"
             @cancelEditing="cancelEditing"
+            @error="$emit('error', $event)"
           />
           <textarea
             v-else
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
index c317ec487324d10b2293de17182f1d144e8e5623..b143c52901433fb9c90fb7eb96e144661fb3d7ba 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
@@ -1,22 +1,13 @@
 <script>
 import { GlButton, GlFormCheckbox, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
 import { helpPagePath } from '~/helpers/help_page_helper';
-import { s__, __, sprintf } from '~/locale';
+import { s__, __ } from '~/locale';
 import Tracking from '~/tracking';
-import {
-  I18N_WORK_ITEM_ERROR_UPDATING,
-  sprintfWorkItem,
-  STATE_OPEN,
-  STATE_EVENT_REOPEN,
-  STATE_EVENT_CLOSE,
-  TRACKING_CATEGORY_SHOW,
-  i18n,
-} from '~/work_items/constants';
+import { STATE_OPEN, TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
 import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
 import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
 import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import { getUpdateWorkItemMutation } from '~/work_items/components/update_work_item';
+import WorkItemStateToggleButton from '~/work_items/components/work_item_state_toggle_button.vue';
 
 export default {
   i18n: {
@@ -25,6 +16,7 @@ export default {
       'Notes|Internal notes are only visible to members with the role of Reporter or higher',
     ),
     addInternalNote: __('Add internal note'),
+    cancelButtonText: __('Cancel'),
   },
   constantOptions: {
     markdownDocsPath: helpPagePath('user/markdown'),
@@ -34,6 +26,7 @@ export default {
     MarkdownEditor,
     GlFormCheckbox,
     GlIcon,
+    WorkItemStateToggleButton,
   },
   directives: {
     GlTooltip: GlTooltipDirective,
@@ -123,14 +116,6 @@ export default {
     isWorkItemOpen() {
       return this.workItemState === STATE_OPEN;
     },
-    toggleWorkItemStateText() {
-      return this.isWorkItemOpen
-        ? sprintf(__('Close %{workItemType}'), { workItemType: this.workItemType.toLowerCase() })
-        : sprintf(__('Reopen %{workItemType}'), { workItemType: this.workItemType.toLowerCase() });
-    },
-    cancelButtonText() {
-      return this.isNewDiscussion ? this.toggleWorkItemStateText : __('Cancel');
-    },
     commentButtonTextComputed() {
       return this.isNoteInternal ? this.$options.i18n.addInternalNote : this.commentButtonText;
     },
@@ -166,48 +151,6 @@ export default {
       this.$emit('cancelEditing');
       clearDraft(this.autosaveKey);
     },
-    async toggleWorkItemState() {
-      const input = {
-        id: this.workItemId,
-        stateEvent: this.isWorkItemOpen ? STATE_EVENT_CLOSE : STATE_EVENT_REOPEN,
-      };
-
-      this.updateInProgress = true;
-
-      try {
-        this.track('updated_state');
-
-        const { mutation, variables } = getUpdateWorkItemMutation({
-          workItemParentId: this.workItemParentId,
-          input,
-        });
-
-        const { data } = await this.$apollo.mutate({
-          mutation,
-          variables,
-        });
-
-        const errors = data.workItemUpdate?.errors;
-
-        if (errors?.length) {
-          this.$emit('error', i18n.updateError);
-        }
-      } catch (error) {
-        const msg = sprintfWorkItem(I18N_WORK_ITEM_ERROR_UPDATING, this.workItemType);
-
-        this.$emit('error', msg);
-        Sentry.captureException(error);
-      }
-
-      this.updateInProgress = false;
-    },
-    cancelButtonAction() {
-      if (this.isNewDiscussion) {
-        this.toggleWorkItemState();
-      } else {
-        this.cancelEditing();
-      }
-    },
   },
 };
 </script>
@@ -257,13 +200,23 @@ export default {
           @click="$emit('submitForm', { commentText, isNoteInternal })"
           >{{ commentButtonTextComputed }}
         </gl-button>
+        <work-item-state-toggle-button
+          v-if="isNewDiscussion"
+          class="gl-ml-3"
+          :work-item-id="workItemId"
+          :work-item-state="workItemState"
+          :work-item-type="workItemType"
+          can-update
+          @error="$emit('error', $event)"
+        />
         <gl-button
+          v-else
           data-testid="cancel-button"
           category="primary"
           class="gl-ml-3"
           :loading="updateInProgress"
-          @click="cancelButtonAction"
-          >{{ cancelButtonText }}
+          @click="cancelEditing"
+          >{{ $options.i18n.cancelButtonText }}
         </gl-button>
       </form>
     </div>
diff --git a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
index c727075eaac8671a111382d27f2d34d22ad6b61d..139f0f7919c95c17db2a8efef226f601fd385c38 100644
--- a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
@@ -11,7 +11,6 @@ import {
   WIDGET_TYPE_START_AND_DUE_DATE,
   WIDGET_TYPE_WEIGHT,
 } from '../constants';
-import WorkItemState from './work_item_state.vue';
 import WorkItemDueDate from './work_item_due_date.vue';
 import WorkItemAssignees from './work_item_assignees.vue';
 import WorkItemLabels from './work_item_labels.vue';
@@ -23,7 +22,6 @@ export default {
     WorkItemMilestone,
     WorkItemAssignees,
     WorkItemDueDate,
-    WorkItemState,
     WorkItemWeight: () => import('ee_component/work_items/components/work_item_weight.vue'),
     WorkItemProgress: () => import('ee_component/work_items/components/work_item_progress.vue'),
     WorkItemIteration: () => import('ee_component/work_items/components/work_item_iteration.vue'),
@@ -97,12 +95,6 @@ export default {
 
 <template>
   <div class="work-item-attributes-wrapper">
-    <work-item-state
-      :work-item="workItem"
-      :work-item-parent-id="workItemParentId"
-      :can-update="canUpdate"
-      @error="$emit('error', $event)"
-    />
     <work-item-assignees
       v-if="workItemAssignees"
       :can-update="canUpdate"
diff --git a/app/assets/javascripts/work_items/components/work_item_created_updated.vue b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
index 78a86aa49a46a811cc355f0e19ccb0c622e08292..af5293ebe9128c1415d3b7619c9598cfb0e883f9 100644
--- a/app/assets/javascripts/work_items/components/work_item_created_updated.vue
+++ b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
@@ -2,6 +2,7 @@
 import { GlAvatarLink, GlSprintf } from '@gitlab/ui';
 import { getIdFromGraphQLId } from '~/graphql_shared/utils';
 import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vue';
 import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
 
 export default {
@@ -9,6 +10,7 @@ export default {
     GlAvatarLink,
     GlSprintf,
     TimeAgoTooltip,
+    WorkItemStateBadge,
   },
   inject: ['fullPath'],
   props: {
@@ -31,6 +33,9 @@ export default {
     authorId() {
       return getIdFromGraphQLId(this.author.id);
     },
+    workItemState() {
+      return this.workItem?.state;
+    },
   },
   apollo: {
     workItem: {
@@ -54,7 +59,8 @@ export default {
 
 <template>
   <div class="gl-mb-3">
-    <span data-testid="work-item-created">
+    <work-item-state-badge v-if="workItemState" :work-item-state="workItemState" />
+    <span data-testid="work-item-created" class="gl-vertical-align-middle">
       <gl-sprintf v-if="author.name" :message="__('Created %{timeAgo} by %{author}')">
         <template #timeAgo>
           <time-ago-tooltip :time="createdAt" />
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index dc4065f981211748c613612c61692fe63df53ec5..238df236b6bfc0e5e2c6c4f34fb85269ad94a915 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -49,6 +49,7 @@ import WorkItemDescription from './work_item_description.vue';
 import WorkItemNotes from './work_item_notes.vue';
 import WorkItemDetailModal from './work_item_detail_modal.vue';
 import WorkItemAwardEmoji from './work_item_award_emoji.vue';
+import WorkItemStateToggleButton from './work_item_state_toggle_button.vue';
 
 export default {
   i18n,
@@ -57,6 +58,7 @@ export default {
   },
   isLoggedIn: isLoggedIn(),
   components: {
+    WorkItemStateToggleButton,
     GlAlert,
     GlBadge,
     GlButton,
@@ -445,6 +447,14 @@ export default {
             class="gl-mr-3 gl-cursor-help"
             >{{ __('Confidential') }}</gl-badge
           >
+          <work-item-state-toggle-button
+            v-if="canUpdate"
+            :work-item-id="workItem.id"
+            :work-item-state="workItem.state"
+            :work-item-parent-id="workItemParentId"
+            :work-item-type="workItemType"
+            @error="updateError = $event"
+          />
           <work-item-todos
             v-if="showWorkItemCurrentUserTodos"
             :work-item-id="workItem.id"
diff --git a/app/assets/javascripts/work_items/components/work_item_state_badge.vue b/app/assets/javascripts/work_items/components/work_item_state_badge.vue
new file mode 100644
index 0000000000000000000000000000000000000000..1d1bc7352b1c5d4407dbffbc5e9faf54fb9ae8c4
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_state_badge.vue
@@ -0,0 +1,41 @@
+<script>
+import { GlBadge } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { STATE_OPEN } from '../constants';
+
+export default {
+  components: {
+    GlBadge,
+  },
+  props: {
+    workItemState: {
+      type: String,
+      required: true,
+    },
+  },
+  computed: {
+    isWorkItemOpen() {
+      return this.workItemState === STATE_OPEN;
+    },
+    stateText() {
+      return this.isWorkItemOpen ? __('Open') : __('Closed');
+    },
+    workItemStateIcon() {
+      return this.isWorkItemOpen ? 'issue-open-m' : 'issue-close';
+    },
+    workItemStateVariant() {
+      return this.isWorkItemOpen ? 'success' : 'info';
+    },
+  },
+};
+</script>
+
+<template>
+  <gl-badge
+    :icon="workItemStateIcon"
+    :variant="workItemStateVariant"
+    class="gl-mr-2 gl-vertical-align-middle"
+  >
+    {{ stateText }}
+  </gl-badge>
+</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_state.vue b/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue
similarity index 58%
rename from app/assets/javascripts/work_items/components/work_item_state.vue
rename to app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue
index 3880ae25c8cac9f7edd8d0aaa9b432ab24e3e2ae..0ea308454663825413a7b9fbc8497e1bdc0d161b 100644
--- a/app/assets/javascripts/work_items/components/work_item_state.vue
+++ b/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue
@@ -1,26 +1,35 @@
 <script>
+import { GlButton } from '@gitlab/ui';
 import * as Sentry from '@sentry/browser';
 import Tracking from '~/tracking';
+import { __, sprintf } from '~/locale';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { getUpdateWorkItemMutation } from '~/work_items/components/update_work_item';
 import {
   sprintfWorkItem,
   I18N_WORK_ITEM_ERROR_UPDATING,
   STATE_OPEN,
-  STATE_CLOSED,
   STATE_EVENT_CLOSE,
   STATE_EVENT_REOPEN,
   TRACKING_CATEGORY_SHOW,
 } from '../constants';
-import { getUpdateWorkItemMutation } from './update_work_item';
-import ItemState from './item_state.vue';
 
 export default {
   components: {
-    ItemState,
+    GlButton,
   },
   mixins: [Tracking.mixin()],
   props: {
-    workItem: {
-      type: Object,
+    workItemState: {
+      type: String,
+      required: true,
+    },
+    workItemId: {
+      type: String,
+      required: true,
+    },
+    workItemType: {
+      type: String,
       required: true,
     },
     workItemParentId: {
@@ -28,11 +37,6 @@ export default {
       required: false,
       default: null,
     },
-    canUpdate: {
-      type: Boolean,
-      required: false,
-      default: false,
-    },
   },
   data() {
     return {
@@ -40,8 +44,16 @@ export default {
     };
   },
   computed: {
-    workItemType() {
-      return this.workItem.workItemType?.name;
+    isWorkItemOpen() {
+      return this.workItemState === STATE_OPEN;
+    },
+    toggleWorkItemStateText() {
+      const baseText = this.isWorkItemOpen
+        ? __('Close %{workItemType}')
+        : __('Reopen %{workItemType}');
+      return capitalizeFirstCharacter(
+        sprintf(baseText, { workItemType: this.workItemType.toLowerCase() }),
+      );
     },
     tracking() {
       return {
@@ -52,25 +64,10 @@ export default {
     },
   },
   methods: {
-    updateWorkItemState(newState) {
-      const stateEventMap = {
-        [STATE_OPEN]: STATE_EVENT_REOPEN,
-        [STATE_CLOSED]: STATE_EVENT_CLOSE,
-      };
-
-      const stateEvent = stateEventMap[newState];
-
-      this.updateWorkItem(stateEvent);
-    },
-
-    async updateWorkItem(updatedState) {
-      if (!updatedState) {
-        return;
-      }
-
+    async updateWorkItem() {
       const input = {
-        id: this.workItem.id,
-        stateEvent: updatedState,
+        id: this.workItemId,
+        stateEvent: this.isWorkItemOpen ? STATE_EVENT_CLOSE : STATE_EVENT_REOPEN,
       };
 
       this.updateInProgress = true;
@@ -107,10 +104,10 @@ export default {
 </script>
 
 <template>
-  <item-state
-    v-if="workItem.state"
-    :state="workItem.state"
-    :disabled="updateInProgress || !canUpdate"
-    @changed="updateWorkItemState"
-  />
+  <gl-button
+    :loading="updateInProgress"
+    data-testid="work-item-state-toggle"
+    @click="updateWorkItem"
+    >{{ toggleWorkItemStateText }}</gl-button
+  >
 </template>
diff --git a/ee/spec/features/projects/work_items/okr_spec.rb b/ee/spec/features/projects/work_items/okr_spec.rb
index b6f6a1333b8f0cfa955d640343114ded3051adf0..30d7c23a34ca9237a5fb81ca197687e9cc16a785 100644
--- a/ee/spec/features/projects/work_items/okr_spec.rb
+++ b/ee/spec/features/projects/work_items/okr_spec.rb
@@ -99,7 +99,7 @@
 
     let(:work_item) { objective }
 
-    it_behaves_like 'work items status'
+    it_behaves_like 'work items toggle status button'
     it_behaves_like 'work items assignees'
     it_behaves_like 'work items labels'
     it_behaves_like 'work items progress'
@@ -295,7 +295,7 @@
 
     let(:work_item) { key_result }
 
-    it_behaves_like 'work items status'
+    it_behaves_like 'work items toggle status button'
     it_behaves_like 'work items assignees'
     it_behaves_like 'work items labels'
     it_behaves_like 'work items progress'
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
index e996a76b1c5697ac5413ee1af1d790686a50fe70..618d3e2efd0e3b1a68a51bc960e610f3269277fd 100644
--- a/spec/features/projects/work_items/work_item_spec.rb
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -40,7 +40,7 @@
     end
 
     it_behaves_like 'work items title'
-    it_behaves_like 'work items status'
+    it_behaves_like 'work items toggle status button'
     it_behaves_like 'work items assignees'
     it_behaves_like 'work items labels'
     it_behaves_like 'work items comments', :issue
diff --git a/spec/frontend/work_items/components/item_state_spec.js b/spec/frontend/work_items/components/item_state_spec.js
deleted file mode 100644
index c3bdbfe030e2d7038eeed4ddb8c981cf8dc2271f..0000000000000000000000000000000000000000
--- a/spec/frontend/work_items/components/item_state_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { GlFormSelect } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { STATE_OPEN, STATE_CLOSED } from '~/work_items/constants';
-import ItemState from '~/work_items/components/item_state.vue';
-
-describe('ItemState', () => {
-  let wrapper;
-
-  const findLabel = () => wrapper.find('label').text();
-  const findFormSelect = () => wrapper.findComponent(GlFormSelect);
-  const selectedValue = () => wrapper.find('option:checked').element.value;
-
-  const clickOpen = () => wrapper.findAll('option').at(0).setSelected();
-
-  const createComponent = ({ state = STATE_OPEN, disabled = false } = {}) => {
-    wrapper = mount(ItemState, {
-      propsData: {
-        state,
-        disabled,
-      },
-    });
-  };
-
-  it('renders label and dropdown', () => {
-    createComponent();
-
-    expect(findLabel()).toBe('Status');
-    expect(selectedValue()).toBe(STATE_OPEN);
-  });
-
-  it('renders dropdown for closed', () => {
-    createComponent({ state: STATE_CLOSED });
-
-    expect(selectedValue()).toBe(STATE_CLOSED);
-  });
-
-  it('emits changed event', async () => {
-    createComponent({ state: STATE_CLOSED });
-
-    await clickOpen();
-
-    expect(wrapper.emitted('changed')).toEqual([[STATE_OPEN]]);
-  });
-
-  it('does not emits changed event if clicking selected value', async () => {
-    createComponent({ state: STATE_OPEN });
-
-    await clickOpen();
-
-    expect(wrapper.emitted('changed')).toBeUndefined();
-  });
-
-  describe('form select disabled prop', () => {
-    describe.each`
-      description            | disabled | value
-      ${'when not disabled'} | ${false} | ${undefined}
-      ${'when disabled'}     | ${true}  | ${'disabled'}
-    `('$description', ({ disabled, value }) => {
-      it(`renders form select component with disabled=${value}`, () => {
-        createComponent({ disabled });
-
-        expect(findFormSelect().attributes('disabled')).toBe(value);
-      });
-    });
-  });
-});
diff --git a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
index e6d20dcb0d9bb99e6912540d42c9a8421a272e5f..4b1b7b27ad966338d214e63c01a8d5901f95a11a 100644
--- a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
@@ -247,6 +247,14 @@ describe('Work item add note', () => {
 
         expect(clearDraft).toHaveBeenCalledWith('gid://gitlab/WorkItem/1-comment');
       });
+
+      it('emits error to parent when the comment form emits error', async () => {
+        await createComponent({ isEditing: true, signedIn: true });
+        const error = 'error';
+        findCommentForm().vm.$emit('error', error);
+
+        expect(wrapper.emitted('error')).toEqual([[error]]);
+      });
     });
   });
 
diff --git a/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js b/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js
index 6c00d52aac5bfe039d35fd88f20a6ae1d3c8ac80..dd88f34ae4fbe612ffec049a426c5f1d85b41163 100644
--- a/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js
@@ -6,18 +6,11 @@ import { createMockDirective } from 'helpers/vue_mock_directive';
 import waitForPromises from 'helpers/wait_for_promises';
 import * as autosave from '~/lib/utils/autosave';
 import { ESC_KEY, ENTER_KEY } from '~/lib/utils/keys';
-import {
-  STATE_OPEN,
-  STATE_CLOSED,
-  STATE_EVENT_REOPEN,
-  STATE_EVENT_CLOSE,
-} from '~/work_items/constants';
+import { STATE_OPEN } from '~/work_items/constants';
 import * as confirmViaGlModal from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
 import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
 import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
-import { updateWorkItemMutationResponse, workItemQueryResponse } from 'jest/work_items/mock_data';
+import WorkItemStateToggleButton from '~/work_items/components/work_item_state_toggle_button.vue';
 
 Vue.use(VueApollo);
 
@@ -44,8 +37,7 @@ describe('Work item comment form component', () => {
   const findConfirmButton = () => wrapper.find('[data-testid="confirm-button"]');
   const findInternalNoteCheckbox = () => wrapper.findComponent(GlFormCheckbox);
   const findInternalNoteTooltipIcon = () => wrapper.findComponent(GlIcon);
-
-  const mutationSuccessHandler = jest.fn().mockResolvedValue(updateWorkItemMutationResponse);
+  const findWorkItemToggleStateButton = () => wrapper.findComponent(WorkItemStateToggleButton);
 
   const createComponent = ({
     isSubmitting = false,
@@ -53,10 +45,8 @@ describe('Work item comment form component', () => {
     isNewDiscussion = false,
     workItemState = STATE_OPEN,
     workItemType = 'Task',
-    mutationHandler = mutationSuccessHandler,
   } = {}) => {
     wrapper = shallowMount(WorkItemCommentForm, {
-      apolloProvider: createMockApollo([[updateWorkItemMutation, mutationHandler]]),
       propsData: {
         workItemState,
         workItemId,
@@ -205,61 +195,20 @@ describe('Work item comment form component', () => {
   });
 
   describe('when used as a top level/is a new discussion', () => {
-    describe('cancel button text', () => {
-      it.each`
-        workItemState   | workItemType    | buttonText
-        ${STATE_OPEN}   | ${'Task'}       | ${'Close task'}
-        ${STATE_CLOSED} | ${'Task'}       | ${'Reopen task'}
-        ${STATE_OPEN}   | ${'Objective'}  | ${'Close objective'}
-        ${STATE_CLOSED} | ${'Objective'}  | ${'Reopen objective'}
-        ${STATE_OPEN}   | ${'Key result'} | ${'Close key result'}
-        ${STATE_CLOSED} | ${'Key result'} | ${'Reopen key result'}
-      `(
-        'is "$buttonText" when "$workItemType" state is "$workItemState"',
-        ({ workItemState, workItemType, buttonText }) => {
-          createComponent({ isNewDiscussion: true, workItemState, workItemType });
-
-          expect(findCancelButton().text()).toBe(buttonText);
-        },
-      );
-    });
-
-    describe('Close/reopen button click', () => {
-      it.each`
-        workItemState   | stateEvent
-        ${STATE_OPEN}   | ${STATE_EVENT_CLOSE}
-        ${STATE_CLOSED} | ${STATE_EVENT_REOPEN}
-      `(
-        'calls mutation with "$stateEvent" when workItemState is "$workItemState"',
-        async ({ workItemState, stateEvent }) => {
-          createComponent({ isNewDiscussion: true, workItemState });
-
-          findCancelButton().vm.$emit('click');
-
-          await waitForPromises();
-
-          expect(mutationSuccessHandler).toHaveBeenCalledWith({
-            input: {
-              id: workItemQueryResponse.data.workItem.id,
-              stateEvent,
-            },
-          });
-        },
+    it('emits an error message when the mutation was unsuccessful', async () => {
+      createComponent({
+        isNewDiscussion: true,
+      });
+      findWorkItemToggleStateButton().vm.$emit(
+        'error',
+        'Something went wrong while updating the task. Please try again.',
       );
 
-      it('emits an error message when the mutation was unsuccessful', async () => {
-        createComponent({
-          isNewDiscussion: true,
-          mutationHandler: jest.fn().mockRejectedValue('Error!'),
-        });
-        findCancelButton().vm.$emit('click');
-
-        await waitForPromises();
+      await waitForPromises();
 
-        expect(wrapper.emitted('error')).toEqual([
-          ['Something went wrong while updating the task. Please try again.'],
-        ]);
-      });
+      expect(wrapper.emitted('error')).toEqual([
+        ['Something went wrong while updating the task. Please try again.'],
+      ]);
     });
   });
 
diff --git a/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js b/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
index ba9af7b2b6862e148d69bfaf826485f33493b72a..8b7e04854af13edaabc87f863e6446a2ebb20a29 100644
--- a/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
+++ b/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
@@ -1,7 +1,6 @@
 import { shallowMount } from '@vue/test-utils';
 import WorkItemAssignees from '~/work_items/components/work_item_assignees.vue';
 import WorkItemDueDate from '~/work_items/components/work_item_due_date.vue';
-import WorkItemState from '~/work_items/components/work_item_state.vue';
 import WorkItemLabels from '~/work_items/components/work_item_labels.vue';
 import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
 
@@ -13,7 +12,6 @@ describe('WorkItemAttributesWrapper component', () => {
 
   const workItemQueryResponse = workItemResponseFactory({ canUpdate: true, canDelete: true });
 
-  const findWorkItemState = () => wrapper.findComponent(WorkItemState);
   const findWorkItemDueDate = () => wrapper.findComponent(WorkItemDueDate);
   const findWorkItemAssignees = () => wrapper.findComponent(WorkItemAssignees);
   const findWorkItemLabels = () => wrapper.findComponent(WorkItemLabels);
@@ -40,14 +38,6 @@ describe('WorkItemAttributesWrapper component', () => {
     });
   };
 
-  describe('work item state', () => {
-    it('renders the work item state', () => {
-      createComponent();
-
-      expect(findWorkItemState().exists()).toBe(true);
-    });
-  });
-
   describe('assignees widget', () => {
     it('renders assignees component when widget is returned from the API', () => {
       createComponent();
diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js
index 7ceae935d2d719745a206fd886f99fdc5afb1258..84d9dba93aebc6d1caeb77af32d8cbf8b640068e 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -24,6 +24,7 @@ import WorkItemTitle from '~/work_items/components/work_item_title.vue';
 import WorkItemTree from '~/work_items/components/work_item_links/work_item_tree.vue';
 import WorkItemNotes from '~/work_items/components/work_item_notes.vue';
 import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
+import WorkItemStateToggleButton from '~/work_items/components/work_item_state_toggle_button.vue';
 import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
 import WorkItemTodos from '~/work_items/components/work_item_todos.vue';
 import { i18n } from '~/work_items/constants';
@@ -47,6 +48,10 @@ describe('WorkItemDetail component', () => {
   Vue.use(VueApollo);
 
   const workItemQueryResponse = workItemByIidResponseFactory({ canUpdate: true, canDelete: true });
+  const workItemQueryResponseWithCannotUpdate = workItemByIidResponseFactory({
+    canUpdate: false,
+    canDelete: false,
+  });
   const workItemQueryResponseWithoutParent = workItemByIidResponseFactory({
     parent: null,
     canUpdate: true,
@@ -82,6 +87,7 @@ describe('WorkItemDetail component', () => {
   const findWorkItemTwoColumnViewContainer = () => wrapper.findByTestId('work-item-overview');
   const findRightSidebar = () => wrapper.findByTestId('work-item-overview-right-sidebar');
   const triggerPageScroll = () => findIntersectionObserver().vm.$emit('disappear');
+  const findWorkItemStateToggleButton = () => wrapper.findComponent(WorkItemStateToggleButton);
 
   const createComponent = ({
     isModal = false,
@@ -194,6 +200,25 @@ describe('WorkItemDetail component', () => {
     });
   });
 
+  describe('work item state toggle button', () => {
+    describe.each`
+      description                  | canUpdate
+      ${'when user cannot update'} | ${false}
+      ${'when user can update'}    | ${true}
+    `('$description', ({ canUpdate }) => {
+      it(`${canUpdate ? 'is rendered' : 'is not rendered'}`, async () => {
+        createComponent({
+          handler: canUpdate
+            ? jest.fn().mockResolvedValue(workItemQueryResponse)
+            : jest.fn().mockResolvedValue(workItemQueryResponseWithCannotUpdate),
+        });
+        await waitForPromises();
+
+        expect(findWorkItemStateToggleButton().exists()).toBe(canUpdate);
+      });
+    });
+  });
+
   describe('close button', () => {
     describe('when isModal prop is false', () => {
       it('does not render', async () => {
diff --git a/spec/frontend/work_items/components/work_item_state_badge_spec.js b/spec/frontend/work_items/components/work_item_state_badge_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..888d712cc5ae1e52a9538c9281573428fa87566c
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_state_badge_spec.js
@@ -0,0 +1,32 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { STATE_OPEN, STATE_CLOSED } from '~/work_items/constants';
+import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vue';
+
+describe('WorkItemStateBadge', () => {
+  let wrapper;
+
+  const createComponent = ({ workItemState = STATE_OPEN } = {}) => {
+    wrapper = shallowMount(WorkItemStateBadge, {
+      propsData: {
+        workItemState,
+      },
+    });
+  };
+  const findStatusBadge = () => wrapper.findComponent(GlBadge);
+
+  it.each`
+    state           | icon              | stateText   | variant
+    ${STATE_OPEN}   | ${'issue-open-m'} | ${'Open'}   | ${'success'}
+    ${STATE_CLOSED} | ${'issue-close'}  | ${'Closed'} | ${'info'}
+  `(
+    'renders icon as "$icon" and text as "$stateText" when the work item state is "$state"',
+    ({ state, icon, stateText, variant }) => {
+      createComponent({ workItemState: state });
+
+      expect(findStatusBadge().props('icon')).toBe(icon);
+      expect(findStatusBadge().props('variant')).toBe(variant);
+      expect(findStatusBadge().text()).toBe(stateText);
+    },
+  );
+});
diff --git a/spec/frontend/work_items/components/work_item_state_spec.js b/spec/frontend/work_items/components/work_item_state_toggle_button_spec.js
similarity index 60%
rename from spec/frontend/work_items/components/work_item_state_spec.js
rename to spec/frontend/work_items/components/work_item_state_toggle_button_spec.js
index d1262057c730c1c03ba5f77b7e364616d9f30e34..c0b206e5da454b49d316151e5a74e1589010935c 100644
--- a/spec/frontend/work_items/components/work_item_state_spec.js
+++ b/spec/frontend/work_items/components/work_item_state_toggle_button_spec.js
@@ -1,11 +1,11 @@
+import { GlButton } from '@gitlab/ui';
 import { shallowMount } from '@vue/test-utils';
 import Vue from 'vue';
 import VueApollo from 'vue-apollo';
 import createMockApollo from 'helpers/mock_apollo_helper';
 import { mockTracking } from 'helpers/tracking_helper';
 import waitForPromises from 'helpers/wait_for_promises';
-import ItemState from '~/work_items/components/item_state.vue';
-import WorkItemState from '~/work_items/components/work_item_state.vue';
+import WorkItemStateToggleButton from '~/work_items/components/work_item_state_toggle_button.vue';
 import {
   STATE_OPEN,
   STATE_CLOSED,
@@ -16,59 +16,58 @@ import {
 import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
 import { updateWorkItemMutationResponse, workItemQueryResponse } from '../mock_data';
 
-describe('WorkItemState component', () => {
+describe('Work Item State toggle button component', () => {
   let wrapper;
 
   Vue.use(VueApollo);
 
   const mutationSuccessHandler = jest.fn().mockResolvedValue(updateWorkItemMutationResponse);
 
-  const findItemState = () => wrapper.findComponent(ItemState);
+  const findStateToggleButton = () => wrapper.findComponent(GlButton);
+
+  const { id } = workItemQueryResponse.data.workItem;
 
   const createComponent = ({
-    state = STATE_OPEN,
     mutationHandler = mutationSuccessHandler,
     canUpdate = true,
+    workItemState = STATE_OPEN,
+    workItemType = 'Task',
   } = {}) => {
-    const { id, workItemType } = workItemQueryResponse.data.workItem;
-    wrapper = shallowMount(WorkItemState, {
+    wrapper = shallowMount(WorkItemStateToggleButton, {
       apolloProvider: createMockApollo([[updateWorkItemMutation, mutationHandler]]),
       propsData: {
-        workItem: {
-          id,
-          state,
-          workItemType,
-        },
+        workItemId: id,
+        workItemState,
+        workItemType,
         canUpdate,
       },
     });
   };
 
-  it('renders state', () => {
-    createComponent();
-
-    expect(findItemState().props('state')).toBe(workItemQueryResponse.data.workItem.state);
-  });
-
-  describe('item state disabled prop', () => {
-    describe.each`
-      description             | canUpdate | value
-      ${'when cannot update'} | ${false}  | ${true}
-      ${'when can update'}    | ${true}   | ${false}
-    `('$description', ({ canUpdate, value }) => {
-      it(`renders item state component with disabled=${value}`, () => {
-        createComponent({ canUpdate });
-
-        expect(findItemState().props('disabled')).toBe(value);
-      });
-    });
+  describe('work item State button text', () => {
+    it.each`
+      workItemState   | workItemType    | buttonText
+      ${STATE_OPEN}   | ${'Task'}       | ${'Close task'}
+      ${STATE_CLOSED} | ${'Task'}       | ${'Reopen task'}
+      ${STATE_OPEN}   | ${'Objective'}  | ${'Close objective'}
+      ${STATE_CLOSED} | ${'Objective'}  | ${'Reopen objective'}
+      ${STATE_OPEN}   | ${'Key result'} | ${'Close key result'}
+      ${STATE_CLOSED} | ${'Key result'} | ${'Reopen key result'}
+    `(
+      'is "$buttonText" when "$workItemType" state is "$workItemState"',
+      ({ workItemState, workItemType, buttonText }) => {
+        createComponent({ workItemState, workItemType });
+
+        expect(findStateToggleButton().text()).toBe(buttonText);
+      },
+    );
   });
 
   describe('when updating the state', () => {
     it('calls a mutation', () => {
       createComponent();
 
-      findItemState().vm.$emit('changed', STATE_CLOSED);
+      findStateToggleButton().vm.$emit('click');
 
       expect(mutationSuccessHandler).toHaveBeenCalledWith({
         input: {
@@ -80,10 +79,10 @@ describe('WorkItemState component', () => {
 
     it('calls a mutation with REOPEN', () => {
       createComponent({
-        state: STATE_CLOSED,
+        workItemState: STATE_CLOSED,
       });
 
-      findItemState().vm.$emit('changed', STATE_OPEN);
+      findStateToggleButton().vm.$emit('click');
 
       expect(mutationSuccessHandler).toHaveBeenCalledWith({
         input: {
@@ -96,7 +95,7 @@ describe('WorkItemState component', () => {
     it('emits an error message when the mutation was unsuccessful', async () => {
       createComponent({ mutationHandler: jest.fn().mockRejectedValue('Error!') });
 
-      findItemState().vm.$emit('changed', STATE_CLOSED);
+      findStateToggleButton().vm.$emit('click');
       await waitForPromises();
 
       expect(wrapper.emitted('error')).toEqual([
@@ -109,7 +108,7 @@ describe('WorkItemState component', () => {
 
       createComponent();
 
-      findItemState().vm.$emit('changed', STATE_CLOSED);
+      findStateToggleButton().vm.$emit('click');
       await waitForPromises();
 
       expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_state', {
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 4c15b68245843db51d00a56ade0318a4effc1c28..97407d93cb02d02c3d848c07e0975dbb185a03ae 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -15,17 +15,17 @@
   end
 end
 
-RSpec.shared_examples 'work items status' do
-  let(:state_selector) { '[data-testid="work-item-state-select"]' }
+RSpec.shared_examples 'work items toggle status button' do
+  let(:state_button) { '[data-testid="work-item-state-toggle"]' }
 
   it 'successfully shows and changes the status of the work item' do
-    expect(find(state_selector)).to have_content 'Open'
+    expect(find(state_button, match: :first)).to have_content 'Close'
 
-    find(state_selector).select("Closed")
+    find(state_button, match: :first).click
 
     wait_for_requests
 
-    expect(find(state_selector)).to have_content 'Closed'
+    expect(find(state_button, match: :first)).to have_content 'Reopen'
     expect(work_item.reload.state).to eq('closed')
   end
 end