Skip to content
animorio
IT
All components

The add to cart button

Buttons, TransitionsGSAPMediumCompressed weight: Demo 5.0 KBGSAP 28 KBFreeDownload the zip

Add to cart: pressed, the bag hops and flies off with the words, and the pill closes up into a counter with minus, number and plus while a +1 rises out of it; at one the minus is a bin, which opens the counter back into the button.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The add to cart button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/outfit@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the button: pressed, the bag hops and the pill closes up into a counter (minus, number, plus) with a +1
         rising out of it. At one the minus is a bin, and the bin turns the counter back into the button -->
    <div class="cart" data-cart>
      <div class="cart__pill" data-pill>
        <button class="cart__add" type="button" data-add data-autoclic>
          <svg class="cart__bag" viewBox="0 0 24 24" aria-hidden="true" data-bag><path d="M5.5 8.5h13l-1 11.5h-11zM9 8.5V7a3 3 0 0 1 6 0v1.5"/></svg>
          <span data-add-label>Add to cart</span>
        </button>
        <div class="cart__stepper" role="group" aria-label="Quantity" data-stepper>
          <button class="cart__minus" type="button" data-minus>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path class="cart__dash" data-dash d="M6.5 12h11"/><path class="cart__bin" data-bin d="M6 8h12M10 8V6.5h4V8M7.5 8l.8 10.5h7.4L16.5 8M10.5 11.5v4M13.5 11.5v4"/></svg>
          </button>
          <span class="cart__count" data-count></span>
          <button class="cart__plus" type="button" aria-label="Add one more" data-plus>
            <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6v12M6 12h12"/></svg>
          </button>
        </div>
      </div>
      <span class="cart__pop" aria-hidden="true" data-pop>+1</span>
      <p class="sr" role="status" aria-live="polite" data-said></p>
    </div>
  </main>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

11 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The add to cart button” from Animorio and fit it into my site

What it does

On a black background a light pill with a bag and the words Add to cart. Pressed, the bag hops and flies off upwards together with the words, the pill closes up with a little bounce and squashes for a moment like jelly, and inside, one after the other, come a red bin on a light disc, a white plus on a black disc and the number 1 between them, all with a pop that overshoots and comes back; above the pill a +1 rises and fades. The plus adds one (the number rolls up and another +1 rises), up to 9, where it shakes instead; the minus takes one away and the number rolls down. At two the bin turns into a minus, spinning, and at one it is a bin again. The bin opens the counter back into the button: the three pieces shrink away, the pill widens and the bag and the words come back from above. When the page opens the pill rises and the bag hops.

How it works

Two things in one pill

Inside the pill are the button and the counter, one over the other, as wide as their content; the pill cuts what sticks out and is as wide as what shows. Both widths are measured from the content, and again when the typeface arrives (with a ResizeObserver), so they are never written by hand.

The change

GSAP takes the pill’s width from the button’s to the counter’s in MORPH seconds with back.out, while scaleY goes 0.9, 1.04 and 1. The bag rises and turns, then flies off with the words; the minus, the plus and the number come in with scale from 0.3 and back.out(SPRING), a few hundredths of a second apart. Going back is the same in reverse.

The number and the +1

The number rolls as in a counter: the new figure comes in below the old one and they go up together in ROLL seconds (down when taking away). The +1 is a word above the pill that rises 46 pixels and fades.

The minus and the bin

They are two paths in the same button: going from one to the other, the one leaving turns 90 degrees as it shrinks and the one arriving comes in turning the other way with back.out. The name for screen readers changes too: Remove one, or Remove from cart.

Keyboard

The counter is a group with its own name (Quantity) and a status line says every number. With the keyboard the focus follows: from the button to the plus when the counter appears, and from the bin to the button when it goes back. Not with a finger, because Safari on iPhone would draw the focus ring on it.

Values to change

NameFileDefaultWhat it changes
MAXscript.js9The most you can put in the cart.
MORPHscript.js0.55The seconds of the pill closing up into the counter, and opening back.
ROLLscript.js0.4The seconds a figure of the number takes to roll.
SPRINGscript.js2How far the minus, the number and the plus overshoot as they pop in.

Try them in the Playground

When to use it

For a product card in an online shop, a menu to order from, a shopping list: wherever you add something and then choose how many without moving.

On phones

The pill keeps its size, which fits any screen. The counter’s buttons are 44 pixels, the right size for a finger, and answer at once even when tapped quickly.

With reduced motion

The button and the counter swap at once, with no hops or bounces; the number changes at once, no +1, no shake at the top, and the minus turns into the bin without spinning.

Pitfalls

  • The button and the counter sit one over the other with visibility: hidden on the one that does not show: with display: none they could not be measured, and without hiding them the Tab key would also land on the invisible one.
  • The pill must be centred by its container (here a grid), so it stays in the middle as it closes up: growing from one side only, its centre would move.
  • A quick tap on the plus must not wait: the buttons have touch-action: manipulation, or on iPhone every tap would wait for a possible double tap.
  • The +1 is centred with the translate property and moved with GSAP: GSAP’s inline transform would wipe out a translate(-50%) written inside transform in the CSS.

Libraries

GSAP 3.15.0, Outfit (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 5.0 KB; the libraries: GSAP 28 KB.

Testing

Tested on 12 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All components