usePageInView
Tracks whether the page is visible, so you can pause work while the user is on another tab.
usePageInView tracks whether the page is visible to the user. Its current property is false while the page's tab is in the background or its window is minimised.
const pageInView = usePageInView(); Use it to pause videos, animations and other ongoing work while nobody can see them, and resume when the user comes back.
<script lang="ts">
import { useAnimate, usePageInView, type AnimationPlaybackControls } from "motion-sv";
const pageInView = usePageInView();
const [scope, animate] = useAnimate<HTMLDivElement>();
let progress: AnimationPlaybackControls | undefined;
$effect(() => {
progress = animate(".fill", { scaleX: [0, 1] }, { duration: 5, ease: "linear", repeat: Infinity });
});
// Pause while the tab is hidden, so the bar picks up where it left off
$effect(() => {
if (pageInView.current) progress?.play();
else progress?.pause();
});
</script>
<div class="story" bind:this={scope.current}>
<div class="track"><div class="fill"></div></div>
<p>Switch to another tab and back. The bar pauses while the page is hidden.</p>
</div>
<style>
.story {
display: flex;
flex-direction: column;
gap: 16px;
width: min(320px, 100%);
padding: 16px;
border-radius: 16px;
background: rgb(255 0 136 / 0.12);
}
.track {
height: 6px;
border-radius: 3px;
background: rgb(255 0 136 / 0.2);
overflow: hidden;
}
.fill {
height: 100%;
background: #ff0088;
transform: scaleX(0);
transform-origin: left;
}
p {
margin: 0;
font-size: 14px;
}
</style> Usage
Import usePageInView from motion-sv:
import { usePageInView } from "motion-sv"; Call it at the top level of your component's <script>. It returns an object whose current property is true while the page is visible:
<script lang="ts">
import { usePageInView } from "motion-sv";
const pageInView = usePageInView();
</script>
<p>{pageInView.current ? "Visible" : "Hidden"}</p> current is reactive, so an $effect that reads it re-runs whenever the page is shown or hidden. For instance, to pause a video while the user is on another tab:
<script lang="ts">
import { usePageInView } from "motion-sv";
const pageInView = usePageInView();
let video = $state<HTMLVideoElement>();
$effect(() => {
if (!video) return;
if (pageInView.current) video.play();
else video.pause();
});
</script>
<video bind:this={video} src="/intro.mp4" muted loop></video> Pausing animations
Browsers stop running animation frames in background tabs, but an animation's clock keeps running. When the user comes back, it has jumped ahead, and they've missed part of it.
To pick up where they left off, pause animations while the page is hidden. With useAnimate, use the animation's playback controls:
<script lang="ts">
import { useAnimate, usePageInView, type AnimationPlaybackControls } from "motion-sv";
const pageInView = usePageInView();
const [scope, animate] = useAnimate<HTMLDivElement>();
let progress: AnimationPlaybackControls | undefined;
$effect(() => {
progress = animate(".fill", { scaleX: [0, 1] }, { duration: 5, repeat: Infinity });
});
$effect(() => {
if (pageInView.current) progress?.play();
else progress?.pause();
});
</script>