diff --git a/app/assets/javascripts/graphql_shared/issuable_client.js b/app/assets/javascripts/graphql_shared/issuable_client.js
index 4c867b656a3aef18b8a44499ff76cf9fa29b48b7..493ef4b18f5c3900aa086e7fd5df0704f544a661 100644
--- a/app/assets/javascripts/graphql_shared/issuable_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_client.js
@@ -18,6 +18,7 @@ import isExpandedHierarchyTreeChildQuery from '~/work_items/graphql/client/is_ex
 import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql';
 import activeDiscussionQuery from '~/work_items/components/design_management/graphql/client/active_design_discussion.query.graphql';
 import { updateNewWorkItemCache, workItemBulkEdit } from '~/work_items/graphql/resolvers';
+import { preserveDetailsState } from '~/work_items/utils';
 
 export const config = {
   typeDefs,
@@ -65,6 +66,21 @@ export const config = {
           merge: true,
         },
       },
+      WorkItemWidgetDescription: {
+        fields: {
+          descriptionHtml: {
+            merge(_, incoming) {
+              const el = document.querySelector('.work-item-description');
+              if (!el) {
+                return incoming;
+              }
+
+              const descriptionHtml = preserveDetailsState(el, incoming);
+              return descriptionHtml || incoming;
+            },
+          },
+        },
+      },
       WorkItemWidgetNotes: {
         fields: {
           // If we add any key args, the discussions field becomes discussions({"filter":"ONLY_ACTIVITY","first":10}) and
diff --git a/app/assets/javascripts/work_items/utils.js b/app/assets/javascripts/work_items/utils.js
index 74d72e89e7550961e8a2c4a8d544306f782f4a9f..f0ece9e9dbd972f2b1e1bdd00abc15215da3d107 100644
--- a/app/assets/javascripts/work_items/utils.js
+++ b/app/assets/javascripts/work_items/utils.js
@@ -8,6 +8,7 @@ import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
 import {
   NEW_WORK_ITEM_IID,
   WIDGET_TYPE_ASSIGNEES,
+  WIDGET_TYPE_DESCRIPTION,
   WIDGET_TYPE_DESIGNS,
   WIDGET_TYPE_HEALTH_STATUS,
   WIDGET_TYPE_HIERARCHY,
@@ -45,6 +46,9 @@ export const isWeightWidget = (widget) => widget.type === WIDGET_TYPE_WEIGHT;
 export const findHierarchyWidgets = (widgets) =>
   widgets?.find((widget) => widget.type === WIDGET_TYPE_HIERARCHY);
 
+export const findDescriptionWidget = (workItem) =>
+  workItem?.widgets?.find((widget) => widget.type === WIDGET_TYPE_DESCRIPTION);
+
 export const findLinkedItemsWidget = (workItem) =>
   workItem.widgets?.find((widget) => widget.type === WIDGET_TYPE_LINKED_ITEMS);
 
@@ -351,3 +355,35 @@ export const formatSelectOptionForCustomField = ({ id, value }) => ({
   text: value,
   value: id,
 });
+
+/**
+ * This function takes the `descriptionHtml` property of a work item and updates any `<details>`
+ * elements within it with an `open=true` attribute to match the current state in the DOM.
+ *
+ * This is necessary for scenarios such as toggling a checkbox with an opened `<details>` element,
+ * which causes the `<details>` element to close when the frontend receives the backend response.
+ *
+ * @param {HTMLElement} element DOM element containing <details> elements
+ * @param {string} descriptionHtml The incoming HTML description
+ * @returns {string|null} The updated HTML for the incoming description that preserves the state of the <details> elements
+ */
+export const preserveDetailsState = (element, descriptionHtml) => {
+  const previousDetails = Array.from(element.getElementsByTagName('details'));
+  if (!previousDetails.some((details) => details.open)) {
+    return null;
+  }
+
+  const nextTemplate = document.createElement('div');
+  nextTemplate.innerHTML = descriptionHtml; // eslint-disable-line no-unsanitized/property
+  const nextDetails = nextTemplate.getElementsByTagName('details');
+  if (previousDetails.length !== nextDetails.length) {
+    return null;
+  }
+
+  Array.from(nextDetails).forEach((details, i) => {
+    if (previousDetails[i].open) {
+      details.setAttribute('open', 'true');
+    }
+  });
+  return nextTemplate.innerHTML;
+};
diff --git a/spec/frontend/work_items/utils_spec.js b/spec/frontend/work_items/utils_spec.js
index 56f4b35df8aaac88ee8d6aa3d83a047050d460ce..dc8b0fd7c5174b55e0bf6df0453a6acca13108ed 100644
--- a/spec/frontend/work_items/utils_spec.js
+++ b/spec/frontend/work_items/utils_spec.js
@@ -1,10 +1,10 @@
 import {
   NEW_WORK_ITEM_IID,
-  WORK_ITEM_TYPE_ENUM_ISSUE,
-  WORK_ITEM_TYPE_ENUM_EPIC,
-  STATE_OPEN,
   STATE_CLOSED,
+  STATE_OPEN,
+  WORK_ITEM_TYPE_ENUM_EPIC,
   WORK_ITEM_TYPE_ENUM_INCIDENT,
+  WORK_ITEM_TYPE_ENUM_ISSUE,
   WORK_ITEM_TYPE_ENUM_KEY_RESULT,
   WORK_ITEM_TYPE_ENUM_OBJECTIVE,
   WORK_ITEM_TYPE_ENUM_REQUIREMENTS,
@@ -36,6 +36,7 @@ import {
   getItems,
   canRouterNav,
   formatSelectOptionForCustomField,
+  preserveDetailsState,
 } from '~/work_items/utils';
 import { useLocalStorageSpy } from 'helpers/local_storage_helper';
 import { TYPE_EPIC } from '~/issues/constants';
@@ -402,3 +403,50 @@ describe('formatSelectOptionForCustomField', () => {
     expect(formatSelectOptionForCustomField(data)).toEqual(result);
   });
 });
+
+describe('preserveDetailsState', () => {
+  const descriptionHtml = '<details><summary>Test</summary><p>Content</p></details>';
+  let element;
+
+  beforeEach(() => {
+    element = document.createElement('div');
+  });
+
+  it('returns null when there are no open details elements', () => {
+    element.innerHTML = '<details><summary>Test</summary><p>Content</p></details>';
+
+    expect(preserveDetailsState(element, descriptionHtml)).toBe(null);
+  });
+
+  it('returns null when number of details elements does not match', () => {
+    element.innerHTML = '<details open><summary>Test</summary><p>Content</p></details>';
+    const newDescriptionHtml =
+      '<details><summary>Test</summary><p>Content</p></details><details><summary>Test 2</summary><p>Content 2</p></details>';
+
+    expect(preserveDetailsState(element, newDescriptionHtml)).toBe(null);
+  });
+
+  it('preserves open state of details elements', () => {
+    element.innerHTML = '<details open><summary>Test</summary><p>Content</p></details>';
+
+    expect(preserveDetailsState(element, descriptionHtml)).toBe(
+      '<details open="true"><summary>Test</summary><p>Content</p></details>',
+    );
+  });
+
+  it('handles multiple details elements', () => {
+    element.innerHTML = `
+      <details open><summary>Test 1</summary><p>Content 1</p></details>
+      <details><summary>Test 2</summary><p>Content 2</p></details>
+    `;
+    const newDescriptionHtml = `
+      <details><summary>Test 1</summary><p>Content 1</p></details>
+      <details><summary>Test 2</summary><p>Content 2</p></details>
+    `;
+
+    expect(preserveDetailsState(element, newDescriptionHtml)).toBe(`
+      <details open="true"><summary>Test 1</summary><p>Content 1</p></details>
+      <details><summary>Test 2</summary><p>Content 2</p></details>
+    `);
+  });
+});