diff --git a/app/assets/javascripts/profile/edit/components/profile_edit_app.vue b/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
index 815b8742500d31d2e99026ce69bd701001490485..eedb5d7764e605cbf49300dce836438c9f7895bd 100644
--- a/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
+++ b/app/assets/javascripts/profile/edit/components/profile_edit_app.vue
@@ -3,7 +3,6 @@ import { nextTick } from 'vue';
 import { GlForm, GlButton } from '@gitlab/ui';
 import { VARIANT_DANGER, VARIANT_INFO, createAlert } from '~/alert';
 import axios from '~/lib/utils/axios_utils';
-import { readFileAsDataURL } from '~/lib/utils/file_utility';
 import SetStatusForm from '~/set_status_modal/set_status_form.vue';
 import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
 import { isUserBusy, computedClearStatusAfterValue } from '~/set_status_modal/utils';
@@ -106,20 +105,12 @@ export default {
         this.updateProfileSettings = false;
       }
     },
-    async syncHeaderAvatars() {
-      const dataURL = await readFileAsDataURL(this.avatarBlob);
-
-      const elements = gon?.use_new_navigation
-        ? ['[data-testid="user-dropdown"] .gl-avatar']
-        : ['.header-user-avatar', '.js-sidebar-user-avatar'];
-
-      elements.forEach((selector) => {
-        const node = document.querySelector(selector);
-        if (!node) return;
-
-        node.setAttribute('src', dataURL);
-        node.setAttribute('srcset', dataURL);
-      });
+    syncHeaderAvatars() {
+      document.dispatchEvent(
+        new CustomEvent('userAvatar:update', {
+          detail: { url: URL.createObjectURL(this.avatarBlob) },
+        }),
+      );
     },
     onBlobChange(blob) {
       this.avatarBlob = blob;
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index 4d3824f910ce7c72aec8df4f73fc07df68010ffb..16f0110a1afe1b2fce1c34c167ca797fab4b879e 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -89,12 +89,9 @@ export default class Profile {
   }
 
   updateHeaderAvatar() {
-    if (gon?.use_new_navigation) {
-      $('[data-testid="user-dropdown"] .gl-avatar').attr('src', this.avatarGlCrop.dataURL);
-    } else {
-      $('.header-user-avatar').attr('src', this.avatarGlCrop.dataURL);
-      $('.js-sidebar-user-avatar').attr('src', this.avatarGlCrop.dataURL);
-    }
+    const url = URL.createObjectURL(this.avatarGlCrop.getBlob());
+
+    document.dispatchEvent(new CustomEvent('userAvatar:update', { detail: { url } }));
   }
 
   setRepoRadio() {
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
index db769df873fd72a5bfe2326991aee7e0fda828e0..5dab74374dfaaac6924c892f5efee6fefe26d9f1 100644
--- a/app/assets/javascripts/super_sidebar/components/user_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -59,9 +59,13 @@ export default {
   data() {
     return {
       setStatusModalReady: false,
+      updatedAvatarUrl: null,
     };
   },
   computed: {
+    avatarUrl() {
+      return this.updatedAvatarUrl || this.data.avatar_url;
+    },
     toggleText() {
       return sprintf(__('%{user} user’s menu'), { user: this.data.name });
     },
@@ -190,7 +194,16 @@ export default {
       };
     },
   },
+  mounted() {
+    document.addEventListener('userAvatar:update', this.updateAvatar);
+  },
+  unmounted() {
+    document.removeEventListener('userAvatar:update', this.updateAvatar);
+  },
   methods: {
+    updateAvatar(event) {
+      this.updatedAvatarUrl = event.detail?.url;
+    },
     onShow() {
       this.initBuyCIMinsCallout();
     },
@@ -240,7 +253,7 @@ export default {
           <gl-avatar
             :size="24"
             :entity-name="data.name"
-            :src="data.avatar_url"
+            :src="avatarUrl"
             aria-hidden="true"
             data-testid="user-avatar-content"
           />
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index 83eb7cb989e36f032b94b70077532b5a316f5ea9..5d121d9eeba9c9b06e4a4be21cb2d4bdc2c9aa2a 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -18,8 +18,10 @@
 
       wait_for_all_requests
 
-      data_uri = find('.avatar-image .gl-avatar')['src']
-      within_testid('user-dropdown') { expect(find('.gl-avatar')['src']).to eq data_uri }
+      within_testid('user-dropdown') do
+        # We are setting a blob URL
+        expect(find('.gl-avatar')['src']).to start_with 'blob:'
+      end
 
       visit profile_path
 
diff --git a/spec/frontend/profile/edit/components/profile_edit_app_spec.js b/spec/frontend/profile/edit/components/profile_edit_app_spec.js
index 31a368aefa916b3ea99f03cfe054f61dc1929c43..39bf597352bd6b518c5adbbde86e48f16e46cce8 100644
--- a/spec/frontend/profile/edit/components/profile_edit_app_spec.js
+++ b/spec/frontend/profile/edit/components/profile_edit_app_spec.js
@@ -3,7 +3,6 @@ import MockAdapter from 'axios-mock-adapter';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import waitForPromises from 'helpers/wait_for_promises';
 
-import { readFileAsDataURL } from '~/lib/utils/file_utility';
 import axios from '~/lib/utils/axios_utils';
 import ProfileEditApp from '~/profile/edit/components/profile_edit_app.vue';
 import UserAvatar from '~/profile/edit/components/user_avatar.vue';
@@ -103,6 +102,8 @@ describe('Profile Edit App', () => {
     });
 
     it('syncs header avatars', async () => {
+      jest.spyOn(document, 'dispatchEvent');
+      jest.spyOn(URL, 'createObjectURL');
       mockAxios.onPut(stubbedProfilePath).reply(200, {
         message: successMessage,
       });
@@ -112,7 +113,8 @@ describe('Profile Edit App', () => {
 
       await waitForPromises();
 
-      expect(readFileAsDataURL).toHaveBeenCalledWith(mockAvatarFile);
+      expect(URL.createObjectURL).toHaveBeenCalledWith(mockAvatarFile);
+      expect(document.dispatchEvent).toHaveBeenCalledWith(new CustomEvent('userAvatar:update'));
     });
 
     it('contains changes from the status form', async () => {
diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js
index ba675c8b3f514570629c02941fee03c52bdf3785..4af3247693be942108c497e9c60f5dcb1644703b 100644
--- a/spec/frontend/super_sidebar/components/user_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/user_menu_spec.js
@@ -78,6 +78,20 @@ describe('UserMenu component', () => {
       });
     });
 
+    it('updates avatar url on custom avatar update event', async () => {
+      const url = `${userMenuMockData.avatar_url}-new-avatar`;
+
+      document.dispatchEvent(new CustomEvent('userAvatar:update', { detail: { url } }));
+      await nextTick();
+
+      const avatar = toggle.findComponent(GlAvatar);
+      expect(avatar.exists()).toBe(true);
+      expect(avatar.props()).toMatchObject({
+        entityName: userMenuMockData.name,
+        src: url,
+      });
+    });
+
     it('renders screen reader text', () => {
       expect(toggle.find('.gl-sr-only').text()).toBe(`${userMenuMockData.name} user’s menu`);
     });