snap
snap is a GSAP helper that rounds a value to the nearest step in an increment or the nearest entry in an array of allowed values. It exists in two forms: the `gsap.utils.snap()` utility you call yourself, and the `snap` property you drop into a tween to snap a value as it animates.
Updated July 1, 2026
How snap works
gsap.utils.snap(snapTo, value) takes a snap target and a value, and returns the value rounded to the nearest allowed point. Pass a number for snapTo and it snaps to the nearest multiple. Pass an array and it snaps to the nearest entry in that array.
Omit the value and you get a reusable function back. This is the form you want inside a drag handler or a scroll callback that snaps the same way on every frame, so you build the snapper once instead of re-parsing the config each call.
The second form is the snap property on a tween. GSAP snaps the animated value to the nearest increment as the tween runs, so a scale or position lands on a clean step instead of an arbitrary in-between value.
Snap the endpoint, not every frame
snap tween property snaps the FINAL value, then eases toward it, so the motion stays smooth and only the resting point is locked to the grid. It does not step the animation frame by frame.Use it for
- Draggable carousels and sliders that settle on the nearest card after a throw
- Rotary dials and knobs that lock to fixed angles (
gsap.utils.snap(45)for 45-degree stops) - Grid-based drag where items should land on cell boundaries, not arbitrary pixels
- Value pickers and steppers where only certain values are allowed (
snap([0, 25, 50, 100])) - Scroll-driven counters that tick to whole numbers instead of showing fractional in-between states
Use something else when
- You want continuous, free positioning with no fixed stops, then leave snap out entirely
- You need values to wrap around a range (0-360 back to 0) rather than round to a step, use
gsap.utils.wrap - You need a random value pinned to an increment,
gsap.utils.random(0, 500, 5)snaps its own output - You want a full physics throw with momentum before settling, reach for Draggable plus InertiaPlugin and pass snap as the
snapconfig there so the inertia lands on a stop - The stops are DOM scroll positions, native CSS
scroll-snaphandles that without GSAP
Used in these Annnimate components
Snapping is what turns a loose drag into something that feels deliberate. Two components in the library sit on opposite sides of that choice:
- The Circular Slider snaps every drag to the nearest card. It computes
sliceAngle = 360 / numItems, then passes(endVal) => gsap.utils.snap(sliceAngle, endVal)into Draggable's inertiasnapconfig, so a throw carries momentum and then settles exactly on a card angle instead of stopping mid-rotation. - The Infinite Draggable Grid is the deliberate counter-case. It drags freely with no snap, wrapping items infinitely instead of locking to cells. Adding a
snapto its drag position is exactly the change you would make to turn it into a grid that clicks into place.
Snap and Draggable are both free now
See it running in production
Common questions
- What is the difference between gsap.utils.snap and the snap tween property?
gsap.utils.snap(snapTo, value)is a plain function you call yourself to round one value, useful in drag or scroll handlers. Thesnaptween property (for examplesnap: { x: 20 }) is passed intogsap.to()and snaps the animated property's resting value as the tween finishes. Same rounding logic, two entry points: one imperative, one declarative.- How do I snap to a set of specific values instead of an even increment?
- Pass an array instead of a number.
gsap.utils.snap([0, 100, 200, 500], 140)returns 100, the nearest allowed value. This is the pattern for pickers, breakpoints, or any case where the stops are not evenly spaced. - Why should I omit the value argument?
- Omitting the value returns a reusable function preloaded with the snap config:
const s = gsap.utils.snap(10); s(23)gives 20. Inside a mousemove or drag handler that fires many times, you build the snapper once and call it per frame instead of re-passing the increment every time. It reads cleaner and does less work. - Does snap make my drag throw feel instant or does it keep the momentum?
- On its own,
gsap.utils.snapjust returns a rounded number, no motion. To keep the momentum of a throw and then land on a snapped stop, pass a snapping function into Draggable's InertiaPluginsnapconfig. That is how the Circular Slider carries a flick's velocity and still settles exactly on a card. - When should I use CSS scroll-snap instead of GSAP snap?
- If you are snapping the page or a scroll container to element boundaries, use native CSS
scroll-snap-typeandscroll-snap-align. It is lighter and needs no JavaScript. Reach for GSAP snap when you are rounding an animated value, a drag position, a rotation, a counter, that is not a native scroll position.
