diff --git a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
index 7ddb71cbde..c048a22207 100644
--- a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte
@@ -99,7 +99,7 @@
           ]}
           name="vcodec"
           isEdited={config.ffmpeg.targetVideoCodec !== savedConfig.ffmpeg.targetVideoCodec}
-          on:select={() => (config.ffmpeg.acceptedVideoCodecs = [config.ffmpeg.targetVideoCodec])}
+          onSelect={() => (config.ffmpeg.acceptedVideoCodecs = [config.ffmpeg.targetVideoCodec])}
         />
 
         <SettingSelect
@@ -114,7 +114,7 @@
           ]}
           name="acodec"
           isEdited={config.ffmpeg.targetAudioCodec !== savedConfig.ffmpeg.targetAudioCodec}
-          on:select={() =>
+          onSelect={() =>
             config.ffmpeg.acceptedAudioCodecs.includes(config.ffmpeg.targetAudioCodec)
               ? null
               : config.ffmpeg.acceptedAudioCodecs.push(config.ffmpeg.targetAudioCodec)}
diff --git a/web/src/lib/components/admin-page/settings/image/image-settings.svelte b/web/src/lib/components/admin-page/settings/image/image-settings.svelte
index a7b47920fd..d6fc814b98 100644
--- a/web/src/lib/components/admin-page/settings/image/image-settings.svelte
+++ b/web/src/lib/components/admin-page/settings/image/image-settings.svelte
@@ -96,7 +96,7 @@
           title={$t('admin.image_prefer_wide_gamut')}
           subtitle={$t('admin.image_prefer_wide_gamut_setting_description')}
           checked={config.image.colorspace === Colorspace.P3}
-          on:toggle={(e) => (config.image.colorspace = e.detail ? Colorspace.P3 : Colorspace.Srgb)}
+          onToggle={(isChecked) => (config.image.colorspace = isChecked ? Colorspace.P3 : Colorspace.Srgb)}
           isEdited={config.image.colorspace !== savedConfig.image.colorspace}
           {disabled}
         />
@@ -105,7 +105,7 @@
           title={$t('admin.image_prefer_embedded_preview')}
           subtitle={$t('admin.image_prefer_embedded_preview_setting_description')}
           checked={config.image.extractEmbedded}
-          on:toggle={() => (config.image.extractEmbedded = !config.image.extractEmbedded)}
+          onToggle={() => (config.image.extractEmbedded = !config.image.extractEmbedded)}
           isEdited={config.image.extractEmbedded !== savedConfig.image.extractEmbedded}
           {disabled}
         />
diff --git a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
index ae9fda8c69..5f03784c42 100644
--- a/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/video-wrapper-viewer.svelte
@@ -15,5 +15,13 @@
 {#if projectionType === ProjectionType.EQUIRECTANGULAR}
   <PanoramaViewer asset={{ id: assetId, type: AssetTypeEnum.Video }} />
 {:else}
-  <VideoNativeViewer {loopVideo} {checksum} {assetId} {onPreviousAsset} {onNextAsset} />
+  <VideoNativeViewer
+    {loopVideo}
+    {checksum}
+    {assetId}
+    {onPreviousAsset}
+    {onNextAsset}
+    on:onVideoEnded
+    on:onVideoStarted
+  />
 {/if}
diff --git a/web/src/lib/components/faces-page/people-list.svelte b/web/src/lib/components/faces-page/people-list.svelte
index 230c8750ae..10626a6a93 100644
--- a/web/src/lib/components/faces-page/people-list.svelte
+++ b/web/src/lib/components/faces-page/people-list.svelte
@@ -32,7 +32,7 @@
 >
   <div class="grid-col-2 grid gap-8 md:grid-cols-3 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10">
     {#each showPeople as person (person.id)}
-      <FaceThumbnail {person} on:click={() => onSelect(person)} circle border selectable />
+      <FaceThumbnail {person} onClick={() => onSelect(person)} circle border selectable />
     {/each}
   </div>
 </div>
diff --git a/web/src/lib/components/faces-page/people-search.svelte b/web/src/lib/components/faces-page/people-search.svelte
index cfd4c8f29a..2a952b8145 100644
--- a/web/src/lib/components/faces-page/people-search.svelte
+++ b/web/src/lib/components/faces-page/people-search.svelte
@@ -83,8 +83,8 @@
     bind:name={searchName}
     {showLoadingSpinner}
     {placeholder}
-    on:reset={handleReset}
-    on:search={({ detail }) => handleSearch(detail.force ?? false)}
+    onReset={handleReset}
+    onSearch={({ force }) => handleSearch(force ?? false)}
   />
 {:else}
   <input
diff --git a/web/src/lib/components/faces-page/unmerge-face-selector.svelte b/web/src/lib/components/faces-page/unmerge-face-selector.svelte
index 753e46c219..dca2fd2516 100644
--- a/web/src/lib/components/faces-page/unmerge-face-selector.svelte
+++ b/web/src/lib/components/faces-page/unmerge-face-selector.svelte
@@ -168,7 +168,7 @@
               circle
               selectable
               thumbnailSize={180}
-              on:click={handleRemoveSelectedPerson}
+              onClick={handleRemoveSelectedPerson}
             />
           </div>
         </div>
diff --git a/web/src/lib/components/forms/tag-asset-form.svelte b/web/src/lib/components/forms/tag-asset-form.svelte
index 7500a6faac..b5e358ec96 100644
--- a/web/src/lib/components/forms/tag-asset-form.svelte
+++ b/web/src/lib/components/forms/tag-asset-form.svelte
@@ -52,7 +52,7 @@
   <form on:submit|preventDefault={handleSubmit} autocomplete="off" id="create-tag-form">
     <div class="my-4 flex flex-col gap-2">
       <Combobox
-        on:select={({ detail: option }) => handleSelect(option)}
+        onSelect={handleSelect}
         label={$t('tag')}
         options={allTags.map((tag) => ({ id: tag.id, label: tag.value, value: tag.id }))}
         placeholder={$t('search_tags')}
diff --git a/web/src/lib/components/share-page/individual-shared-viewer.svelte b/web/src/lib/components/share-page/individual-shared-viewer.svelte
index af5c54c988..1b5368b133 100644
--- a/web/src/lib/components/share-page/individual-shared-viewer.svelte
+++ b/web/src/lib/components/share-page/individual-shared-viewer.svelte
@@ -84,7 +84,7 @@
       {/if}
     </AssetSelectControlBar>
   {:else}
-    <ControlAppBar on:close={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}>
+    <ControlAppBar onClose={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}>
       <svelte:fragment slot="leading">
         <ImmichLogoSmallLink width={innerWidth} />
       </svelte:fragment>
diff --git a/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte b/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte
index 2b8c678543..3bd462f997 100644
--- a/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte
+++ b/web/src/lib/components/shared-components/purchasing/purchase-activation-success.svelte
@@ -20,7 +20,7 @@
       title={$t('show_supporter_badge')}
       subtitle={$t('show_supporter_badge_description')}
       bind:checked={$preferences.purchase.showSupportBadge}
-      on:toggle={({ detail }) => setSupportBadgeVisibility(detail)}
+      onToggle={setSupportBadgeVisibility}
     />
   </div>
 
diff --git a/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte b/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte
index f1cd0c8596..3ac8cb8d5a 100644
--- a/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte
+++ b/web/src/lib/components/shared-components/search-bar/search-camera-section.svelte
@@ -56,7 +56,7 @@
     <div class="w-full">
       <Combobox
         label={$t('make')}
-        on:select={({ detail }) => (filters.make = detail?.value)}
+        onSelect={(option) => (filters.make = option?.value)}
         options={asComboboxOptions(makes)}
         placeholder={$t('search_camera_make')}
         selectedOption={asSelectedOption(makeFilter)}
@@ -66,7 +66,7 @@
     <div class="w-full">
       <Combobox
         label={$t('model')}
-        on:select={({ detail }) => (filters.model = detail?.value)}
+        onSelect={(option) => (filters.model = option?.value)}
         options={asComboboxOptions(models)}
         placeholder={$t('search_camera_model')}
         selectedOption={asSelectedOption(modelFilter)}
diff --git a/web/src/lib/components/shared-components/search-bar/search-location-section.svelte b/web/src/lib/components/shared-components/search-bar/search-location-section.svelte
index ce265d0030..71912264ed 100644
--- a/web/src/lib/components/shared-components/search-bar/search-location-section.svelte
+++ b/web/src/lib/components/shared-components/search-bar/search-location-section.svelte
@@ -73,7 +73,7 @@
     <div class="w-full">
       <Combobox
         label={$t('country')}
-        on:select={({ detail }) => (filters.country = detail?.value)}
+        onSelect={(option) => (filters.country = option?.value)}
         options={asComboboxOptions(countries)}
         placeholder={$t('search_country')}
         selectedOption={asSelectedOption(filters.country)}
@@ -83,7 +83,7 @@
     <div class="w-full">
       <Combobox
         label={$t('state')}
-        on:select={({ detail }) => (filters.state = detail?.value)}
+        onSelect={(option) => (filters.state = option?.value)}
         options={asComboboxOptions(states)}
         placeholder={$t('search_state')}
         selectedOption={asSelectedOption(filters.state)}
@@ -93,7 +93,7 @@
     <div class="w-full">
       <Combobox
         label={$t('city')}
-        on:select={({ detail }) => (filters.city = detail?.value)}
+        onSelect={(option) => (filters.city = option?.value)}
         options={asComboboxOptions(cities)}
         placeholder={$t('search_city')}
         selectedOption={asSelectedOption(filters.city)}
diff --git a/web/src/lib/components/shared-components/settings/setting-combobox.svelte b/web/src/lib/components/shared-components/settings/setting-combobox.svelte
index 502cd94cce..722af048a5 100644
--- a/web/src/lib/components/shared-components/settings/setting-combobox.svelte
+++ b/web/src/lib/components/shared-components/settings/setting-combobox.svelte
@@ -32,14 +32,7 @@
     <p class="text-sm dark:text-immich-dark-fg">{subtitle}</p>
   </div>
   <div class="flex items-center">
-    <Combobox
-      label={title}
-      hideLabel={true}
-      {selectedOption}
-      {options}
-      placeholder={comboboxPlaceholder}
-      on:select={({ detail }) => onSelect(detail)}
-    />
+    <Combobox label={title} hideLabel={true} {selectedOption} {options} placeholder={comboboxPlaceholder} {onSelect} />
     <slot />
   </div>
 </div>
diff --git a/web/src/lib/components/user-settings-page/app-settings.svelte b/web/src/lib/components/user-settings-page/app-settings.svelte
index de4bbafdd9..e6ce8f6aae 100644
--- a/web/src/lib/components/user-settings-page/app-settings.svelte
+++ b/web/src/lib/components/user-settings-page/app-settings.svelte
@@ -99,7 +99,7 @@
           title={$t('theme_selection')}
           subtitle={$t('theme_selection_description')}
           bind:checked={$colorTheme.system}
-          on:toggle={handleToggleColorTheme}
+          onToggle={handleToggleColorTheme}
         />
       </div>
 
@@ -119,7 +119,7 @@
           title={$t('default_locale')}
           subtitle={$t('default_locale_description')}
           checked={$locale == undefined}
-          on:toggle={handleToggleLocaleBrowser}
+          onToggle={handleToggleLocaleBrowser}
         >
           <p class="mt-2 dark:text-gray-400">{selectedDate}</p>
         </SettingSwitch>
@@ -142,7 +142,7 @@
           title={$t('display_original_photos')}
           subtitle={$t('display_original_photos_setting_description')}
           bind:checked={$alwaysLoadOriginalFile}
-          on:toggle={() => ($alwaysLoadOriginalFile = !$alwaysLoadOriginalFile)}
+          onToggle={() => ($alwaysLoadOriginalFile = !$alwaysLoadOriginalFile)}
         />
       </div>
       <div class="ml-4">
@@ -150,7 +150,7 @@
           title={$t('video_hover_setting')}
           subtitle={$t('video_hover_setting_description')}
           bind:checked={$playVideoThumbnailOnHover}
-          on:toggle={() => ($playVideoThumbnailOnHover = !$playVideoThumbnailOnHover)}
+          onToggle={() => ($playVideoThumbnailOnHover = !$playVideoThumbnailOnHover)}
         />
       </div>
       <div class="ml-4">
@@ -158,7 +158,7 @@
           title={$t('loop_videos')}
           subtitle={$t('loop_videos_description')}
           bind:checked={$loopVideo}
-          on:toggle={() => ($loopVideo = !$loopVideo)}
+          onToggle={() => ($loopVideo = !$loopVideo)}
         />
       </div>
 
diff --git a/web/src/lib/components/user-settings-page/partner-settings.svelte b/web/src/lib/components/user-settings-page/partner-settings.svelte
index ee57e4c688..050e2c42f3 100644
--- a/web/src/lib/components/user-settings-page/partner-settings.svelte
+++ b/web/src/lib/components/user-settings-page/partner-settings.svelte
@@ -177,7 +177,7 @@
               title={$t('show_in_timeline')}
               subtitle={$t('show_in_timeline_setting_description')}
               bind:checked={partner.inTimeline}
-              on:toggle={({ detail }) => handleShowOnTimelineChanged(partner, detail)}
+              onToggle={(isChecked) => handleShowOnTimelineChanged(partner, isChecked)}
             />
           {/if}
         </div>
diff --git a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte
index bf0fd3c874..71f76d07c0 100644
--- a/web/src/lib/components/user-settings-page/user-purchase-settings.svelte
+++ b/web/src/lib/components/user-settings-page/user-purchase-settings.svelte
@@ -115,7 +115,7 @@
           title={$t('show_supporter_badge')}
           subtitle={$t('show_supporter_badge_description')}
           bind:checked={$preferences.purchase.showSupportBadge}
-          on:toggle={({ detail }) => setSupportBadgeVisibility(detail)}
+          onToggle={setSupportBadgeVisibility}
         />
       </div>
 
diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 57d09ed53a..cbdb38192e 100644
--- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -470,7 +470,7 @@
       </AssetSelectControlBar>
     {:else}
       {#if viewMode === ViewMode.VIEW}
-        <ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(backUrl)}>
+        <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(backUrl)}>
           <svelte:fragment slot="trailing">
             {#if isEditor}
               <CircleIconButton
@@ -527,7 +527,7 @@
       {/if}
 
       {#if viewMode === ViewMode.SELECT_ASSETS}
-        <ControlAppBar on:close={handleCloseSelectAssets}>
+        <ControlAppBar onClose={handleCloseSelectAssets}>
           <svelte:fragment slot="leading">
             <p class="text-lg dark:text-immich-dark-fg">
               {#if $timelineSelected.size === 0}
@@ -554,7 +554,7 @@
       {/if}
 
       {#if viewMode === ViewMode.SELECT_THUMBNAIL}
-        <ControlAppBar on:close={() => (viewMode = ViewMode.VIEW)}>
+        <ControlAppBar onClose={() => (viewMode = ViewMode.VIEW)}>
           <svelte:fragment slot="leading">{$t('select_album_cover')}</svelte:fragment>
         </ControlAppBar>
       {/if}
@@ -583,8 +583,8 @@
             isSelectionMode={viewMode === ViewMode.SELECT_THUMBNAIL}
             singleSelect={viewMode === ViewMode.SELECT_THUMBNAIL}
             showArchiveIcon
-            on:select={({ detail: asset }) => handleUpdateThumbnail(asset.id)}
-            on:escape={handleEscape}
+            onSelect={({ id }) => handleUpdateThumbnail(id)}
+            onEscape={handleEscape}
           >
             {#if viewMode !== ViewMode.SELECT_THUMBNAIL}
               <!-- ALBUM TITLE -->
diff --git a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
index 2e109823ed..adbc3cfe69 100644
--- a/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/map/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -113,7 +113,7 @@
 {#if $featureFlags.loaded && $featureFlags.map}
   <UserPageLayout title={data.meta.title}>
     <div class="isolate h-full w-full">
-      <Map hash bind:mapMarkers bind:showSettingsModal on:selected={(event) => onViewAssets(event.detail)} />
+      <Map hash bind:mapMarkers bind:showSettingsModal onSelect={onViewAssets} />
     </div>
   </UserPageLayout>
   <Portal target="body">
diff --git a/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
index b580c4faa5..2caab9de82 100644
--- a/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/partners/[userId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -38,7 +38,7 @@
       <DownloadAction />
     </AssetSelectControlBar>
   {:else}
-    <ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(AppRoute.SHARING)}>
+    <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(AppRoute.SHARING)}>
       <svelte:fragment slot="leading">
         <p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg">
           {data.partner.name}'s photos
diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
index bb648228b9..83019d67cd 100644
--- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -400,7 +400,7 @@
     </AssetSelectControlBar>
   {:else}
     {#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE}
-      <ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(previousRoute)}>
+      <ControlAppBar showBackButton backIcon={mdiArrowLeft} onClose={() => goto(previousRoute)}>
         <svelte:fragment slot="trailing">
           <ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
             <MenuOption
@@ -429,7 +429,7 @@
     {/if}
 
     {#if viewMode === ViewMode.SELECT_PERSON}
-      <ControlAppBar on:close={() => (viewMode = ViewMode.VIEW_ASSETS)}>
+      <ControlAppBar onClose={() => (viewMode = ViewMode.VIEW_ASSETS)}>
         <svelte:fragment slot="leading">{$t('select_featured_photo')}</svelte:fragment>
       </ControlAppBar>
     {/if}
@@ -444,8 +444,8 @@
       {assetInteractionStore}
       isSelectionMode={viewMode === ViewMode.SELECT_PERSON}
       singleSelect={viewMode === ViewMode.SELECT_PERSON}
-      on:select={({ detail: asset }) => handleSelectFeaturePhoto(asset)}
-      on:escape={handleEscape}
+      onSelect={handleSelectFeaturePhoto}
+      onEscape={handleEscape}
     >
       {#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE}
         <!-- Person information block -->
diff --git a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte
index 4649da8205..ba8ee13cc9 100644
--- a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte
@@ -127,7 +127,7 @@
     {assetStore}
     {assetInteractionStore}
     removeAction={AssetAction.ARCHIVE}
-    on:escape={handleEscape}
+    onEscape={handleEscape}
     withStacked
   >
     {#if $preferences.memories.enabled}
diff --git a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte
index da85eb49c8..9c6a8f9e75 100644
--- a/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/search/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -246,7 +246,7 @@
     </div>
   {:else}
     <div class="fixed z-[100] top-0 left-0 w-full">
-      <ControlAppBar on:close={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
+      <ControlAppBar onClose={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
         <div class="w-full flex-1 pl-4">
           <SearchBar grayTheme={false} value={terms.query ?? ''} searchQuery={terms} />
         </div>
diff --git a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
index 5e934143df..67e80f4703 100644
--- a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
+++ b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte
@@ -52,7 +52,7 @@
   };
 </script>
 
-<ControlAppBar backIcon={mdiArrowLeft} on:close={() => goto(AppRoute.SHARING)}>
+<ControlAppBar backIcon={mdiArrowLeft} onClose={() => goto(AppRoute.SHARING)}>
   <svelte:fragment slot="leading">{$t('shared_links')}</svelte:fragment>
 </ControlAppBar>