Blog / JavaScript & Interactions

Add-to-Cart Animation in JavaScript: burst + fly-to-cart

Build an add-to-cart micro-interaction that makes people want to click: magnetic button, particle burst, Bézier-curve fly to the cart icon, and animated counter. Vanilla JS, zero dependency, accessible.

On a store, the add to cart click is the moment that matters. A well-crafted micro-interaction — the item flying to the cart, a small burst, the counter incrementing — confirms the action, makes it satisfying, and removes doubt ("did it work?"). It is a straightforward conversion lever. This article covers the Magnetic Add to Cart effect, the free effect from Effect.Labs' November 2026 Black Friday sprint, built in vanilla JavaScript with zero dependencies, accessible and 60fps.

Definition — Micro-interaction. A small feedback animation triggered by a user action (click, hover). Its role: confirm, guide, and delight. Here, four building blocks combine: magnetic button, particles, fly-to-cart, counter.

1. The magnetic button

The button gently "attracts" the cursor: on pointermove, compute the offset between the cursor and the button center, then apply a proportional translation. On pointerleave, reset.

btn.addEventListener('pointermove', function (e) {
  var r = btn.getBoundingClientRect();
  var mx = e.clientX - (r.left + r.width / 2);
  var my = e.clientY - (r.top + r.height / 2);
  btn.style.transform = 'translate(' + (mx * 0.22) + 'px,' + (my * 0.35) + 'px)';
});
btn.addEventListener('pointerleave', function () { btn.style.transform = ''; });

2. Particle burst

On click, generate about a dozen small particles (simple <span> elements) at the button's position, projected in random directions via CSS custom properties and a keyframe. Lightweight, and auto-cleaned after the animation.

for (var i = 0; i < 14; i++) {
  var p = document.createElement('span');
  p.className = 'atc-particle';
  p.style.left = x0 + 'px'; p.style.top = y0 + 'px';
  var a = Math.random() * 6.2832, d = 24 + Math.random() * 46;
  p.style.setProperty('--dx', Math.cos(a) * d + 'px');
  p.style.setProperty('--dy', Math.sin(a) * d + 'px');
  scene.appendChild(p);
  setTimeout(function () { p.remove(); }, 650); // cleanup
}
.atc-particle { animation: atc-burst .6s ease-out forwards; }
@keyframes atc-burst {
  to { transform: translate(-50%,-50%) translate(var(--dx), var(--dy)) scale(.2); opacity: 0; }
}

3. Fly to cart (Bézier curve)

The heart of the effect: a clone of the item follows a quadratic Bézier curve from the button to the cart icon. The control point placed above both endpoints produces that beautiful arc trajectory.

// P(t) = (1-t)²·P0 + 2(1-t)t·C + t²·P1
var cx = (x0 + x1) / 2, cy = Math.min(y0, y1) - 70; // control point above
(function anim(t) {
  var k = Math.min((t - t0) / 620, 1);
  var e = k < .5 ? 2*k*k : 1 - Math.pow(-2*k+2, 2)/2;  // easing
  var m = 1 - e;
  var x = m*m*x0 + 2*m*e*cx + e*e*x1;
  var y = m*m*y0 + 2*m*e*cy + e*e*y1;
  chip.style.transform = 'translate(-50%,-50%) translate(' + (x-x0) + 'px,' + (y-y0) + 'px) scale(' + (1 - .55*e) + ')';
  if (k < 1) requestAnimationFrame(anim);
  else { chip.remove(); bump(); }   // on arrival: increment the cart
})(t0);

4. Reactive counter

When the clone arrives, increment the badge and replay a small "pop" animation (along with a nudge of the cart icon). The trick to replay a CSS animation: remove the class, force a reflow (void el.offsetWidth), then re-add it.

function bump() {
  n++; countEl.textContent = n;
  countEl.classList.remove('atc-pop'); void countEl.offsetWidth; countEl.classList.add('atc-pop');
}

The full code (magnetic button, burst, fly, and counter together) is available directly on the Buttons catalog pagethis effect is free.

Performance & accessibility

Everything relies on transform/opacity (GPU-composited) and a single requestAnimationFrame per click: smooth even on mobile. The safeguards:

  • A real <button>: keyboard-operable and announced by screen readers.
  • prefers-reduced-motion: skips the magnetism, particles, and fly — keeps only the counter increment (the essential feedback).
  • Cleanup: particles and the clone are removed from the DOM after the animation (no leak).

What ChatGPT and v0 miss

Ask a generator for an "add to cart" animation: you often get a straight-line translate with no character. What gets regularly overlooked:

  • The Bézier curve: the arc (control point above) is what makes the flight feel natural; AI tends to propose a straight line.
  • prefers-reduced-motion: almost never handled — animation forced on users who disabled it.
  • DOM cleanup: particles/clones often stay in the DOM (memory leak on repeated use).
  • The magnetic button on pointermove with a clean reset — rarely included.

FAQ

Can it be used with React, Vue or Svelte?

Yes: vanilla JavaScript, no npm dependency. In React, wrap the logic in a useEffect with cleanup (remove particles/clones on unmount); in Svelte, use onMount/onDestroy.

How do I adapt it for "add to favorites"?

Same mechanics: replace the cart icon with a heart, the flying item with a ❤️, and increment a favorites counter. The code is context-agnostic.

The full, ready-to-use code

This effect is free this month. Copy-paste the code and adapt it to your cart. Access 800+ more premium effects with the subscription.

Join the founders — €9.90 / month