diff --git a/client/src/controllers/SwapController.test.js b/client/src/controllers/SwapController.test.js
index 028ab536f4..f9180071e5 100644
--- a/client/src/controllers/SwapController.test.js
+++ b/client/src/controllers/SwapController.test.js
@@ -1213,4 +1213,196 @@ describe('SwapController', () => {
       document.removeEventListener('w-swap:begin', beginEventHandler);
     });
   });
+
+  describe('performing a content update using HTML in JSON response', () => {
+    let button;
+    let results;
+    const onErrorEvent = jest.fn();
+
+    beforeEach(() => {
+      document.body.innerHTML = `
+      <main>
+        <form
+          action="/path/to/editing-sessions/"
+          method="get"
+          data-controller="w-swap"
+          data-action="submit->w-swap#submitLazy:prevent"
+          data-w-swap-target-value="#editing-sessions"
+          data-w-swap-json-path-value="nested.data.results"
+        >
+          <input name="title" type="text"/>
+          <input name="type" type="hidden" value="some-type" />
+          <button type="submit">Submit<button>
+        </form>
+        <div id="editing-sessions"></div>
+      </main>
+      `;
+
+      button = document.querySelector('button');
+      results = getMockResults({ total: 5 });
+    });
+
+    const expectErrorHandled = async () => {
+      expect(window.location.search).toEqual('');
+      expect(handleError).not.toHaveBeenCalled();
+      expect(global.fetch).not.toHaveBeenCalled();
+
+      button.click();
+
+      jest.runAllTimers(); // update is debounced
+
+      expect(handleError).not.toHaveBeenCalled();
+      expect(global.fetch).toHaveBeenCalledWith(
+        '/path/to/editing-sessions/?title=&type=some-type',
+        expect.any(Object),
+      );
+
+      expect(onErrorEvent).not.toHaveBeenCalled();
+
+      await Promise.resolve(); // trigger next rendering
+
+      await flushPromises(); // resolve all promises
+
+      // eslint-disable-next-line no-console
+      expect(console.error).toHaveBeenLastCalledWith(
+        'Error fetching %s',
+        '/path/to/editing-sessions/?title=&type=some-type',
+        expect.any(Error),
+      );
+      // eslint-disable-next-line no-console
+      expect(console.error.mock.lastCall[2]).toEqual(
+        expect.objectContaining({
+          message:
+            'Unable to parse as JSON at path "nested.data.results" to a string',
+        }),
+      );
+
+      // should not update any HTML
+      expect(document.getElementById('editing-sessions').innerHTML).toEqual('');
+
+      // should have dispatched a custom event for the error
+      expect(onErrorEvent).toHaveBeenCalledTimes(1);
+      expect(onErrorEvent.mock.calls[0][0].detail).toEqual({
+        error: expect.any(Error),
+        requestUrl: '/path/to/editing-sessions/?title=&type=some-type',
+      });
+
+      await Promise.resolve(); // trigger next rendering
+    };
+
+    it('should update the target element with the HTML content from the JSON response', async () => {
+      const onSuccess = new Promise((resolve) => {
+        document.addEventListener('w-swap:success', resolve);
+      });
+
+      const beginEventHandler = jest.fn();
+      document.addEventListener('w-swap:begin', beginEventHandler);
+
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results } } }),
+      );
+
+      expect(handleError).not.toHaveBeenCalled();
+      expect(global.fetch).not.toHaveBeenCalled();
+
+      button.click();
+
+      expect(beginEventHandler).not.toHaveBeenCalled();
+
+      jest.runAllTimers(); // submit is debounced
+
+      // should fire a begin event before the request is made
+      expect(beginEventHandler).toHaveBeenCalledTimes(1);
+      expect(beginEventHandler.mock.calls[0][0].detail).toEqual({
+        requestUrl: '/path/to/editing-sessions/?title=&type=some-type',
+      });
+
+      // visual loading state should be active
+      await Promise.resolve(); // trigger next rendering
+
+      expect(handleError).not.toHaveBeenCalled();
+      expect(global.fetch).toHaveBeenCalledWith(
+        '/path/to/editing-sessions/?title=&type=some-type',
+        expect.any(Object),
+      );
+
+      await Promise.resolve();
+
+      const successEvent = await onSuccess;
+
+      // should dispatch success event
+      expect(successEvent.detail).toEqual({
+        requestUrl: '/path/to/editing-sessions/?title=&type=some-type',
+        results: expect.any(String),
+      });
+
+      // should update HTML
+      expect(
+        document.getElementById('editing-sessions').querySelectorAll('li')
+          .length,
+      ).toBeTruthy();
+
+      await flushPromises();
+
+      // should NOT update the current URL
+      // as the reflect-value attribute is not set
+      expect(window.location.search).toEqual('');
+    });
+
+    it('should handle non-JSON response gracefully', async () => {
+      document.addEventListener('w-swap:error', onErrorEvent);
+
+      fetch.mockResponseSuccessText('<div><p>Some HTML content</p></div>');
+
+      await expectErrorHandled();
+    });
+
+    it('should handle non-existing key gracefully', async () => {
+      document.addEventListener('w-swap:error', onErrorEvent);
+
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { differentKey: results } } }),
+      );
+
+      await expectErrorHandled();
+    });
+
+    it('should handle non-string values gracefully', async () => {
+      document.addEventListener('w-swap:error', onErrorEvent);
+
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results: 123 } } }),
+      );
+
+      await expectErrorHandled();
+
+      jest.clearAllMocks();
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results: true } } }),
+      );
+
+      await expectErrorHandled();
+
+      jest.clearAllMocks();
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results: null } } }),
+      );
+
+      await expectErrorHandled();
+
+      jest.clearAllMocks();
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results: { some: 'object' } } } }),
+      );
+
+      await expectErrorHandled();
+
+      jest.clearAllMocks();
+      fetch.mockResponseSuccessJSON(
+        JSON.stringify({ nested: { data: { results: [1, false, 'hello'] } } }),
+      );
+
+      await expectErrorHandled();
+    });
+  });
 });
diff --git a/client/src/controllers/SwapController.ts b/client/src/controllers/SwapController.ts
index 7bbdc71d3a..7910d6527b 100644
--- a/client/src/controllers/SwapController.ts
+++ b/client/src/controllers/SwapController.ts
@@ -47,6 +47,7 @@ export class SwapController extends Controller<
     loading: { default: false, type: Boolean },
     reflect: { default: false, type: Boolean },
     src: { default: '', type: String },
+    jsonPath: { default: '', type: String },
     target: { default: '#listing-results', type: String },
     wait: { default: 200, type: Number },
   };
@@ -54,12 +55,14 @@ export class SwapController extends Controller<
   declare readonly hasInputTarget: boolean;
   declare readonly hasTargetValue: boolean;
   declare readonly hasUrlValue: boolean;
+  declare readonly hasJsonPathValue: boolean;
   declare readonly inputTarget: HTMLInputElement;
 
   declare iconValue: string;
   declare loadingValue: boolean;
   declare reflectValue: boolean;
   declare srcValue: string;
+  declare jsonPathValue: string;
   declare targetValue: string;
   declare waitValue: number;
 
@@ -267,10 +270,31 @@ export class SwapController extends Controller<
       headers: { 'x-requested-with': 'XMLHttpRequest' },
       signal,
     })
-      .then((response) => {
+      .then(async (response) => {
         if (!response.ok) {
           throw new Error(`HTTP error! Status: ${response.status}`);
         }
+        if (this.jsonPathValue) {
+          let html: unknown;
+          try {
+            const json: Record<string, unknown> = await response.json();
+            html = this.jsonPathValue
+              .split('.')
+              .reduce<unknown>(
+                (acc, key) => (acc as Record<string, unknown>)[key],
+                json,
+              );
+          } catch {
+            html = undefined;
+          }
+
+          if (typeof html !== 'string') {
+            throw new Error(
+              `Unable to parse as JSON at path "${this.jsonPathValue}" to a string`,
+            );
+          }
+          return html;
+        }
         return response.text();
       })
       .then((results) => {