diff --git a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
index a350198d692f63e3b05fe45ce0f45bdf4fb015f7..1f7728e440b82ec771ab565b844b4da5192146c9 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
@@ -1,6 +1,7 @@
 <script>
 import axios from '~/lib/utils/axios_utils';
 import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import { updateDraft, clearDraft, getDraft } from '~/lib/utils/autosave';
 import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '../../constants';
 import MarkdownField from './field.vue';
 
@@ -52,10 +53,15 @@ export default {
       required: false,
       default: false,
     },
+    autosaveKey: {
+      type: String,
+      required: false,
+      default: null,
+    },
   },
   data() {
     return {
-      markdown: this.value || '',
+      markdown: this.value || (this.autosaveKey ? getDraft(this.autosaveKey) : '') || '',
       editingMode: EDITING_MODE_MARKDOWN_FIELD,
       autofocused: false,
     };
@@ -72,19 +78,27 @@ export default {
   watch: {
     value(val) {
       this.markdown = val;
+
+      this.saveDraft();
     },
   },
   mounted() {
     this.autofocusTextarea();
+
+    this.saveDraft();
   },
   methods: {
     updateMarkdownFromContentEditor({ markdown }) {
       this.markdown = markdown;
       this.$emit('input', markdown);
+
+      this.saveDraft();
     },
     updateMarkdownFromMarkdownField({ target }) {
       this.markdown = target.value;
       this.$emit('input', target.value);
+
+      this.saveDraft();
     },
     renderMarkdown(markdown) {
       return axios.post(this.renderMarkdownPath, { text: markdown }).then(({ data }) => data.body);
@@ -110,6 +124,11 @@ export default {
     setEditorAsAutofocused() {
       this.autofocused = true;
     },
+    saveDraft() {
+      if (!this.autosaveKey) return;
+      if (this.markdown) updateDraft(this.autosaveKey, this.markdown);
+      else clearDraft(this.autosaveKey);
+    },
   },
 };
 </script>
diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
index 3e3dd3bcc8858ce6ec91e091b541eedbf7f7e57d..51afb7c499f02cd8467fb2fdb4ec7581814a91f1 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -9,10 +9,13 @@ import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue
 import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
 import MarkdownField from '~/vue_shared/components/markdown/field.vue';
 import { stubComponent } from 'helpers/stub_component';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 
 jest.mock('~/emoji');
 
 describe('vue_shared/component/markdown/markdown_editor', () => {
+  useLocalStorageSpy();
+
   let wrapper;
   const value = 'test markdown';
   const renderMarkdownPath = '/api/markdown';
@@ -64,6 +67,8 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
 
   afterEach(() => {
     mock.restore();
+
+    localStorage.clear();
   });
 
   it('displays markdown field by default', () => {
@@ -102,6 +107,42 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
     });
   });
 
+  describe('autosave', () => {
+    it('automatically saves the textarea value to local storage if autosaveKey is defined', () => {
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: 'This is **markdown**' } });
+
+      expect(localStorage.getItem('autosave/issue/1234')).toBe('This is **markdown**');
+    });
+
+    it("loads value from local storage if autosaveKey is defined, and value isn't", () => {
+      localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
+
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
+
+      expect(findTextarea().element.value).toBe('This is **markdown**');
+    });
+
+    it("doesn't load value from local storage if autosaveKey is defined, and value is", () => {
+      localStorage.setItem('autosave/issue/1234', 'This is **markdown**');
+
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+
+      expect(findTextarea().element.value).toBe('test markdown');
+    });
+
+    it('does not save the textarea value to local storage if autosaveKey is not defined', () => {
+      buildWrapper({ propsData: { value: 'This is **markdown**' } });
+
+      expect(localStorage.setItem).not.toHaveBeenCalled();
+    });
+
+    it('does not save the textarea value to local storage if value is empty', () => {
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234', value: '' } });
+
+      expect(localStorage.setItem).not.toHaveBeenCalled();
+    });
+  });
+
   it('renders markdown field textarea', () => {
     buildWrapper({ propsData: { supportsQuickActions: true } });
 
@@ -158,6 +199,16 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
       expect(wrapper.emitted('input')).toEqual([[newValue]]);
     });
 
+    it('autosaves the markdown value to local storage', async () => {
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+
+      const newValue = 'new value';
+
+      await findTextarea().setValue(newValue);
+
+      expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
+    });
+
     describe('when autofocus is true', () => {
       beforeEach(async () => {
         buildWrapper({ attachTo: document.body, propsData: { autofocus: true } });
@@ -219,7 +270,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
 
   describe(`when editingMode is ${EDITING_MODE_CONTENT_EDITOR}`, () => {
     beforeEach(() => {
-      buildWrapper();
+      buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
       findMarkdownField().vm.$emit('enableContentEditor');
     });
 
@@ -244,6 +295,14 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
       expect(wrapper.emitted('input')).toEqual([[newValue]]);
     });
 
+    it('autosaves the content editor value to local storage', async () => {
+      const newValue = 'new value';
+
+      await findContentEditor().vm.$emit('change', { markdown: newValue });
+
+      expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
+    });
+
     it('bubbles up keydown event', () => {
       const event = new Event('keydown');