diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte
index 67b5e34736..d4b2c09517 100644
--- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte
+++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte
@@ -2,6 +2,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { clickOutside } from '$lib/utils/click-outside';
+ import { imageLoad } from '$lib/utils/image-load';
import { createEventDispatcher } from 'svelte';
import { fade, fly } from 'svelte/transition';
import TrayArrowUp from 'svelte-material-icons/TrayArrowUp.svelte';
@@ -124,13 +125,13 @@
>
{#if user.profileImagePath}
(showProfilePictureFallback = false)}
+ use:imageLoad
+ on:image-load={() => (showProfilePictureFallback = false)}
/>
{/if}
{#if showProfilePictureFallback}
diff --git a/web/src/lib/utils/image-load.ts b/web/src/lib/utils/image-load.ts
new file mode 100644
index 0000000000..a3a7858713
--- /dev/null
+++ b/web/src/lib/utils/image-load.ts
@@ -0,0 +1,38 @@
+import { tick } from 'svelte';
+import type { ActionReturn } from 'svelte/action';
+
+interface Attributes {
+ 'on:image-error'?: (e: CustomEvent) => void;
+ 'on:image-load'?: (e: CustomEvent) => void;
+}
+
+export function imageLoad(img: HTMLImageElement): ActionReturn {
+ const onImageError = () => img.dispatchEvent(new CustomEvent('image-error'));
+ const onImageLoaded = () => img.dispatchEvent(new CustomEvent('image-load'));
+
+ if (img.complete) {
+ // Browser has fetched the image, naturalHeight is used to check
+ // if any loading errors have occurred.
+ const loadingError = img.naturalHeight === 0;
+
+ // Report status after a tick, to make sure event listeners are registered.
+ if (loadingError) {
+ tick().then(onImageError);
+ } else {
+ tick().then(onImageLoaded);
+ }
+
+ return {};
+ }
+
+ // Image has not been loaded yet, report status with event listeners.
+ img.addEventListener('load', onImageLoaded, { once: true });
+ img.addEventListener('error', onImageError, { once: true });
+
+ return {
+ destroy() {
+ img.removeEventListener('load', onImageLoaded);
+ img.removeEventListener('error', onImageError);
+ }
+ };
+}