diff --git a/frontend/src/components/lib/JTransition.vue b/frontend/src/components/lib/JTransition.vue
index eff617a5eb0..d4715f25ea2 100644
--- a/frontend/src/components/lib/JTransition.vue
+++ b/frontend/src/components/lib/JTransition.vue
@@ -3,14 +3,18 @@
:is="props.group ? TransitionGroup : Transition"
class="j-transition"
v-bind="$attrs"
- :name="prefersNoMotion || disabled || isSlow ? undefined : `j-transition-${props.name}`">
+ :name="prefersNoMotion || disabled || isSlow ? undefined : `j-transition-${props.name}`"
+ @before-leave="leaving = true"
+ @after-leave="onNoLeave"
+ @leave-cancelled="onNoLeave">
diff --git a/frontend/src/composables/page-title.ts b/frontend/src/composables/page-title.ts
index 1d9b5a93c1b..df3d5b72fa6 100644
--- a/frontend/src/composables/page-title.ts
+++ b/frontend/src/composables/page-title.ts
@@ -1,5 +1,5 @@
-import { computed, onBeforeUnmount, onMounted, shallowRef, toRef, toValue } from 'vue';
-import { useTitle as _useTitle, watchImmediate, type ReadonlyRefOrGetter } from '@vueuse/core';
+import { computed, onBeforeUnmount, onMounted, shallowRef, toRef, toValue, type MaybeRefOrGetter } from 'vue';
+import { useTitle as _useTitle, watchImmediate } from '@vueuse/core';
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import { isNil } from '@/utils/validation';
@@ -21,7 +21,7 @@ _useTitle(_fullTitle);
*
* Value will be set to default (undefined) when the component consuming this composable is unmounted.
*/
-export function usePageTitle(title?: ReadonlyRefOrGetter>) {
+export function usePageTitle(title?: MaybeRefOrGetter>) {
onMounted(() => {
if (!isNil(title)) {
watchImmediate(toRef(title), val => _title.value = val ?? undefined);
@@ -36,6 +36,6 @@ export function usePageTitle(title?: ReadonlyRefOrGetter>) {
/**
* Same as useTitle, but is a shorthand for items only.
*/
-export function useItemPageTitle(item: ReadonlyRefOrGetter>) {
+export function useItemPageTitle(item: MaybeRefOrGetter>) {
usePageTitle(() => toValue(item)?.Name);
};
diff --git a/frontend/src/composables/use-pausable-effect.ts b/frontend/src/composables/use-pausable-effect.ts
new file mode 100644
index 00000000000..0a5194f53fb
--- /dev/null
+++ b/frontend/src/composables/use-pausable-effect.ts
@@ -0,0 +1,15 @@
+import { getCurrentScope, toRef, watch, type MaybeRefOrGetter } from 'vue';
+
+/**
+ * When the passed argument is truthy, the effect scope of the current component will be paused
+ * until the argument becomes falsy again.
+ *
+ * This is useful for components that need to pause the DOM patching
+ */
+export function usePausableEffect(signal: MaybeRefOrGetter) {
+ const scope = getCurrentScope();
+
+ if (scope) {
+ watch(toRef(signal), val => val ? scope.pause() : scope.resume(), { immediate: true, flush: 'sync' });
+ }
+}