Fly to Cart Button — Add-to-Cart Animation UI

Fly to Cart Button · Buttons · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Position-accurate flight
Measures product and cart positions at click time, so the clone lands precisely on the cart in any layout or scroll position.
Arc trajectory
A three-keyframe path lifts the clone upward at the midpoint and curves down to the cart, like a tossed object.
Shrink-and-fade landing
The clone scales down and fades as it nears the cart, so it appears to drop in rather than collide.
Count bump on arrival
The cart count increments exactly when the clone lands (animation onfinish), so cause and effect line up.
Cart icon pop
A quick scale bump on the cart, restarted via forced reflow, replays on every add.
Web Animations API
Uses element.animate() with runtime-computed keyframes — the deltas can't be hardcoded in CSS.
Click-safe clone
The flying clone is pointer-events: none, so it never blocks interaction during the animation.
Delegated, drop-in
One listener on the product grid handles any number of products, including dynamically added cards.

About this UI Snippet

Fly to Cart Button — Product-to-Cart Flight Animation with Count Bump

Screenshot of the Fly to Cart Button snippet rendered live

The little animation where, on "add to cart," a copy of the product arcs across the screen and lands in the cart icon — which then pops and increments — is a small moment of e-commerce delight that also does real work: it confirms the action and shows the user exactly where their item went. This snippet builds that fly-to-cart effect in plain HTML, CSS, and vanilla JavaScript using the Web Animations API, with no library.

A flying clone from source to target

When a product's "Add to cart" is clicked, fly() measures the product image's position with getBoundingClientRect() and the cart icon's position the same way, then creates a fixed-position clone of the product styled to match it. The clone animates from the product's location to the cart's center, computing the exact pixel delta (dx, dy) between the two so it lands precisely on the cart no matter where either sits on screen or how the page has scrolled. Because both positions are measured at click time, it works for any product card in any layout.

An arc, not a straight line

A straight line from product to cart looks robotic; real "thrown into the cart" motion follows an arc. The animation uses a three-keyframe path with a midpoint that lifts upward (dy × 0.5 − 80px) before descending to the cart, and a slightly overshooting cubic-bezier easing, so the clone curves up and over like a tossed object. It also shrinks (scale(1)scale(.12)) and fades as it approaches, so it appears to "drop into" the cart rather than collide with it. This arc-and-shrink is what sells the illusion.

The cart reacts on arrival

The animation's onfinish callback is where the cart responds: the flying clone is removed, the cart count increments and becomes visible, and the cart icon plays a quick scale "bump" (via a forced-reflow class restart so it replays on every add). Timing the count bump to the *arrival* — not the click — is the key detail: the number changes exactly when the item visually lands, so cause and effect line up and the interaction reads as one continuous motion.

Web Animations API over CSS keyframes

The flight uses element.animate() (the Web Animations API) rather than CSS @keyframes because the keyframe values are computed at runtime — the dx/dy deltas differ for every product and every scroll position, so they can't be hardcoded in a stylesheet. WAA lets you pass dynamic keyframes as JavaScript objects and gives a clean onfinish promise/callback, which is exactly what a position-dependent, one-shot animation needs. The clone is also pointer-events: none so it never blocks clicks mid-flight.

Drop-in for any storefront

The effect attaches via one delegated listener on the product grid, so it works for any number of products and any dynamically-added cards. Each "Add" button carries the product's image reference; in a real store you'd also push the item to your cart state in the onfinish (right when the count bumps). Swap the emoji product images for real photos and the clone will fly the actual product image into the cart.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out the flight geometry by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the fly function computes dx and dy from getBoundingClientRect on both elements at click time rather than using any fixed offset, and why the middle keyframe subtracts 80 from half the vertical delta to create the arc instead of a straight two-keyframe tween. The same assistant can help optimize it — ask whether rapid repeated clicks on multiple Add to cart buttons could create overlapping animate() calls that need throttling, or whether cloning computed styles with getComputedStyle for the background is the cheapest way to match the product image's appearance. It's also useful for extending it: have it fly the actual product photo instead of an emoji, add a subtle rotation to the arc for more physicality, or trigger a wishlist-icon variant of the same flight using a second target element. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an "add to cart" flight animation in plain HTML, CSS, and JavaScript using the Web Animations API (element.animate) — no CSS keyframes, no libraries, since the animation path must be computed at runtime from live element positions.

Requirements:
- A page with a sticky header containing a cart icon button (with a small numeric badge, hidden until the first item is added) and a grid of product cards, each with an image area and an "Add to cart" button.
- On clicking a product's add button, measure that product's image element's bounding rectangle and the cart icon's bounding rectangle with getBoundingClientRect, then create a fixed-position clone element sized and positioned to exactly match the product image (matching its background via getComputedStyle), and append it to the document body.
- Compute the pixel delta between the center of the cart icon and the center of the product image, and animate the clone through three keyframes: starting at its original position and full scale and opacity, passing through a midpoint that is offset horizontally by half the total delta but vertically lifted well above the straight-line path (so the motion arcs upward before descending), and ending at the full delta translation with the clone shrunk to roughly a tenth of its size and partially faded — using an easing curve that overshoots slightly for a tossed, physical feel.
- The clone must have pointer-events disabled so it never blocks clicks while it's mid-flight.
- Only when the animation's onfinish callback fires (not on the initial click) should the clone be removed from the DOM, the cart count be incremented and made visible, and the cart icon play a quick scale "bump" animation restarted via a forced reflow (removing and re-adding an animation class) so it replays correctly on every single add, even in rapid succession.
- Wire this with a single delegated click listener on the product grid container (not one listener per button), so the same code works for any number of product cards.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA mini storefront renders with a sticky cart icon and three products, each with an "Add to cart" button.
  2. 2
    Add a productClick "Add to cart" — a clone of the product arcs up and across the screen into the cart icon.
  3. 3
    Watch the cart reactAs the clone lands, the cart count increments and becomes visible, and the cart icon pops with a bump.
  4. 4
    Add severalAdd multiple products — each flight is independent and the count climbs, bumping on every arrival.
  5. 5
    Use real product imagesReplace the emoji/gradient images with real product photos — the clone flies the actual image.
  6. 6
    Hook up your cartIn the animation's onfinish, push the item to your real cart state right as the count bumps.

Real-world uses

Common Use Cases

E-commerce product grids
Add delight and clear feedback to add-to-cart across a catalog — pair with a mini cart drawer.
Product detail pages
Fly the hero product image into the cart on add, alongside a product quick view.
Quick-shop and category views
Confirm rapid adds visually so shoppers see each item register.
Wishlist and save flows
Adapt the same flight to a "save" or wishlist icon instead of a cart.
Mobile commerce
The motion clearly shows where an item went on small screens where the cart may be off-view.
Learning the Web Animations API
A reference for runtime keyframes and onfinish callbacks — compare with an add to cart button for the in-place confirmation version.

Got questions?

Frequently Asked Questions

fly() reads both the product image's and the cart icon's bounding rectangles with getBoundingClientRect() at the moment of the click, then computes the pixel delta between their centers (dx, dy). The clone is fixed-positioned at the product's spot and animated by exactly that delta, so it lands on the cart regardless of layout, screen size, or scroll position — all measured fresh each time.

The keyframe values depend on runtime measurements — the dx/dy deltas are different for every product and every scroll position, so they can't be written into a static stylesheet. element.animate() accepts keyframes as JavaScript objects (so you can interpolate the computed deltas) and provides a clean onfinish callback to trigger the cart bump exactly when the flight ends, which CSS keyframes can't do as cleanly.

Increment the count in the animation's onfinish callback, not on the click — so the number changes precisely when the flying clone visually lands in the cart. Timing it to arrival makes the cause (item lands) and effect (count rises) read as one continuous motion; bumping on click would make the number jump before the item arrives.

In the onfinish callback (alongside the count bump), dispatch the add-to-cart action to your store/context or POST to your cart API with the product id. Keep the optimistic count bump so the UI feels instant; reconcile with the server response if needed. The animation is purely visual — your cart data is updated separately at the same moment.

In React, attach the click handler and run element.animate() imperatively with refs to the product and cart nodes, updating cart state in onfinish; in Vue, use template refs and @click; in Angular, use ViewChild and (click). The measurement and Web Animations API logic are framework-agnostic — only the cart count moves into reactive state, updated in the onfinish callback.