[Bug]: scrollNext() / scrollPrev() does not reset scrollVelocity, causing bounce when called during active animation

Author: domaine-stijn-slatsCreated Jun 30, 2026Updated Aug 15, 2026
Labelsbugcore

Description

When scrollNext() (or scrollPrev()) is called while a previous scroll animation is still running, the internal scrollVelocity from that animation is not cleared. The new animation then adds to the existing velocity:

javascript
// ScrollBody.seek()
scrollVelocity += displacement / scrollDuration;
scrollVelocity *= scrollFriction;
location.add(scrollVelocity);

And in goTo():

javascript
engine.scrollBody.useBaseFriction().useDuration(options.duration);
engine.scrollTo.index(index, direction);

useBaseFriction() resets friction but does not reset scrollVelocity. The leftover velocity from the previous animation stacks on top of the new displacement / scrollDuration term, pushing the carousel past the target snap point. Embla then corrects back to the snap — visually a noticeable bounce/overshoot.

Steps to reproduce

  1. Create a vertical snap carousel (axis: 'y', loop: false, skipSnaps: false)
  2. Call scrollNext() programmatically in rapid succession (e.g. on each wheel tick with a short debounce)
  3. Observe the bounce/overshoot on each advance

This does not happen with swipe/drag, because drag goes through the proper velocity pipeline and the mouseup release lets the physics settle naturally before any new gesture starts.

Workaround

Zero out velocity manually before calling scrollNext() by setting scrollDuration = 0 for one animation frame (which triggers the isInstant branch that sets scrollVelocity = 0), then calling scrollNext() on the next frame:

javascript
embla.internalEngine().scrollBody.useDuration(0);
requestAnimationFrame(() => embla.scrollNext());

This works but relies on internalEngine() which is not a stable public API.

Expected behaviour

scrollNext() / scrollPrev() should reset scrollVelocity to 0 before starting the new animation, so programmatic calls produce a clean snap with no overshoot regardless of whether an animation is currently running.

Embla version

9.0.0-rc02

Source: davidjerleke/embla-carousel