useSpring
Creates a motion value that animates to its latest target with a spring.
useSpring creates a motion value that animates to its latest target with a spring animation.
You can set the target yourself with set(), or have it follow another motion value. Here, the ball springs towards motion values that track the pointer:
<script lang="ts">
import { motion, useMotionValue, useSpring } from "motion-sv";
const spring = { damping: 3, stiffness: 50, restDelta: 0.001 };
const xPoint = useMotionValue(0);
const yPoint = useMotionValue(0);
const x = useSpring(xPoint, spring);
const y = useSpring(yPoint, spring);
</script>
<motion.div style={{ x, y }} /> <script lang="ts">
import { frame, motion, useMotionValue, useSpring } from "motion-sv";
const spring = { damping: 3, stiffness: 50, restDelta: 0.001 };
const xPoint = useMotionValue(0);
const yPoint = useMotionValue(0);
const x = useSpring(xPoint, spring);
const y = useSpring(yPoint, spring);
function handlePointerMove({ clientX, clientY, currentTarget }: PointerEvent & { currentTarget: HTMLElement }) {
frame.read(() => {
// The ball rests in the middle of the area, so measure the pointer from there
const { left, top, width, height } = currentTarget.getBoundingClientRect();
xPoint.set(clientX - left - width / 2);
yPoint.set(clientY - top - height / 2);
});
}
</script>
<div class="area" role="presentation" onpointermove={handlePointerMove}>
<motion.div class="ball" style={{ x, y }} />
</div>
<style>
.area {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 400px;
}
.area :global(.ball) {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: #ff0088;
}
</style> Usage
Import useSpring from motion-sv:
import { useSpring } from "motion-sv"; Like other hooks, call useSpring during component setup, at the top level of the <script>.
Direct control
Create a spring with a number:
const x = useSpring(0); Now whenever you update it with set(), it animates to its new target with a spring:
x.set(100); To update it immediately, without a spring, use the jump() method:
x.jump(50); <script lang="ts">
import { motion, useSpring } from "motion-sv";
const x = useSpring(0, { visualDuration: 0.5, bounce: 0.3 });
const target = () => (x.get() < 100 ? 200 : 0);
</script>
<div class="stack">
<div class="track">
<motion.div class="box" style={{ x }} />
</div>
<div class="buttons">
<button onclick={() => x.set(target())}>set()</button>
<button onclick={() => x.jump(target())}>jump()</button>
</div>
</div>
<style>
.stack {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
width: 260px;
}
.track {
width: 100%;
padding: 6px;
border-radius: 14px;
background: rgb(255 62 0 / 0.15);
}
.track :global(.box) {
width: 48px;
height: 48px;
border-radius: 10px;
background: #ff3e00;
}
.buttons {
display: flex;
gap: 0.5rem;
}
button {
padding: 8px 20px;
border: none;
border-radius: 8px;
background: #ff3e00;
color: white;
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
cursor: pointer;
}
</style> It also accepts a value with a unit, like "100vh":
const y = useSpring("100vh");
y.set("50vh"); Track another motion value
A spring can follow the latest state of another motion value:
const x = useMotionValue(0);
const y = useSpring(x); The source motion value must hold a number, or a string with a unit, like "10px".
This is a handy way to smooth out values that change abruptly, like scroll progress:
const { scrollYProgress } = useScroll();
const scaleX = useSpring(scrollYProgress, { stiffness: 100, damping: 30 }); Transition
Configure the spring with the usual spring transition options, like stiffness, damping and mass, or visualDuration and bounce:
useSpring(0, { stiffness: 300 });
useSpring(0, { visualDuration: 0.4, bounce: 0.25 }); Changing the transition
To change the spring's options over time, pass a getter instead of an object. When the Svelte state it reads changes, the spring's next animation uses the new options:
<script lang="ts">
import { useMotionValue, useSpring } from "motion-sv";
let isBouncy = $state(false);
const source = useMotionValue(0);
const x = useSpring(source, () => ({ stiffness: 300, damping: isBouncy ? 10 : 40 }));
</script> useFollowValue
useFollowValue works like useSpring, but it can follow its target with other types of transition too, like a tween. Without a type, it uses a spring.
import { useFollowValue } from "motion-sv";
const x = useMotionValue(0);
const tween = useFollowValue(x, { type: "tween", ease: "easeOut" }); <script lang="ts">
import { clamp, motion, useFollowValue, useMotionValue, useSpring } from "motion-sv";
const pointer = useMotionValue(0);
const spring = useSpring(pointer, { stiffness: 300, damping: 20 });
const tween = useFollowValue(pointer, { type: "tween", ease: "easeOut" });
let width = $state(0);
// Centers the 40px dots on the pointer, within the stage
const follow = (event: PointerEvent) => pointer.set(clamp(0, width - 40, event.offsetX - 20));
</script>
<div class="stage" role="presentation" bind:clientWidth={width} onpointermove={follow}>
<div class="row">
<motion.div class="dot pointer" style={{ x: pointer }} />
<span>pointer</span>
</div>
<div class="row">
<motion.div class="dot" style={{ x: spring, background: "#ff0088" }} />
<span>useSpring</span>
</div>
<div class="row">
<motion.div class="dot" style={{ x: tween, background: "#9911ff" }} />
<span>useFollowValue, tween</span>
</div>
</div>
<style>
.stage {
display: flex;
flex-direction: column;
gap: 12px;
width: min(100%, 560px);
padding: 16px 0;
border-radius: 20px;
background: rgb(153 17 255 / 0.08);
cursor: crosshair;
}
.row {
position: relative;
height: 40px;
pointer-events: none;
}
span {
position: absolute;
top: 50%;
right: 16px;
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
font-size: 13px;
opacity: 0.6;
transform: translateY(-50%);
}
.stage :global(.dot) {
width: 40px;
height: 40px;
border-radius: 50%;
}
.stage :global(.pointer) {
box-shadow: inset 0 0 0 3px currentColor;
}
</style> Its source can be a number, a string with a unit, or another motion value. Its options are the same as a transition's, without the repeat and lifecycle options, and like useSpring's, they can be a getter.
skipInitialAnimation
Default: false
When true, the first change from the source motion value jumps straight to the new value instead of animating to it. Later changes animate as usual.
This prevents an unwanted animation when the source starts somewhere other than its initial value, like a scroll position that's restored when the page loads:
const { scrollY } = useScroll();
const y = useFollowValue(scrollY, { skipInitialAnimation: true }); API
useSpring(source, config?)
useFollowValue(source, options?) source
The initial value, as a number or a string with a unit, like "10px", or a motion value to follow.
config / options
The animation's options, as an object, or a getter that returns them. useSpring accepts spring options. useFollowValue accepts any transition options, and skipInitialAnimation.
Returns
A motion value that animates to its latest target.