Skip to content
animorio
IT
All components

The basket with a goal

Carts, Transitions, TextGSAPMediumCompressed weight: Demo 7.6 KBGSAP 28 KBFreeDownload the zip

A farm shop’s basket with a goal, free delivery from a certain total: a bar fills towards it with a little bounce and, when it gets there, turns gold while a small van drives along it to the end; the quantities roll their figures, the prices count, a row dragged to the left goes away and the suggested product flies into the basket.

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 basket with a goal</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/nunito-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the basket with a goal: a bar fills towards free delivery and a small van sets off when it gets there; the
         quantities roll, the totals count, a row dragged aside goes away and a suggestion flies in -->
    <section class="basket" aria-labelledby="basket-title" data-basket data-autoclic>
      <header class="basket__head">
        <h2 class="basket__title" id="basket-title">Your basket</h2>
        <p class="basket__count" data-count></p>
      </header>
      <div class="goal" data-goal>
        <p class="goal__text" aria-live="polite" data-goal-text></p>
        <div class="goal__track" aria-hidden="true">
          <span class="goal__fill" data-fill></span>
          <svg class="goal__van" viewBox="0 0 40 26" data-van><path d="M3 5.5h20v13H3z"/><path d="M23 9.5h7.5l5 5v4H23z"/><circle cx="10" cy="20.5" r="3.2"/><circle cx="29" cy="20.5" r="3.2"/></svg>
        </div>
      </div>
      <ul class="items" aria-label="Products" data-items></ul>
      <div class="extra" data-extra>
        <p class="extra__label">Goes well with</p>
        <button class="extra__add" type="button" data-add></button>
      </div>
      <footer class="basket__foot">
        <p class="basket__total"><span>Subtotal</span><strong data-total></strong></p>
        <button class="basket__go" type="button" data-go>Checkout</button>
      </footer>
      <p class="sr" aria-live="polite" data-live></p>
    </section>
  </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.

36 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 basket with a goal” from Animorio and fit it into my site

What it does

On a black background a dark basket: Your basket with the number of pieces, the line €13 away from free delivery over a green bar with a small van at its tip, three rows (Chestnut honey, Olive oil, Fusilli), each with its little drawing, its price and the minus and plus buttons, then Goes well with and Fig jam +€6, the Subtotal and Checkout. With plus or minus the quantity’s figure leaves the way of the change and the new one comes in from the other side, the row’s price and the subtotal count to the new figure and the bar grows or shrinks with a little bounce. At €45 the bar turns gold, the line says Delivery is free with free popping out, and the van drives to the end rocking on its springs; going back under, the van goes back with the bar. A row dragged to the left uncovers the red under it with Remove: let go past the mark it slides away and the space closes, otherwise it goes back; minus on a quantity of one takes it away too. Fig jam flies in an arc from the suggestion to the new row, which opens meanwhile, and taking it away brings the suggestion back.

How it works

The rolling figures

The quantity changes with a small timeline: the old figure leaves upwards or downwards, depending on the way of the change (yPercent), in 0.12 seconds, and the new one comes in from the other side with back.out. The row’s price and the subtotal count with a tween on a plain object, rounded to 50 cents while they count.

The bar and the goal

The bar is an element scaled in width (scaleX) to the share of the goal reached, in FILL seconds with elastic.out: it may go a little past the mark, up to 102%, and come back. The subtotal instead counts with power3.out, never going past the real figure. Once FREE is reached, a class colours the bar and the figure gold.

The van

The van sits on the tip of the bar; when the goal is reached a timeline takes it to the end in FILL seconds, rocking it with keyframes on y and on the rotation, and pops the word free with back.out. Under the goal it goes back to following the tip.

Dragging a row away

The row listens to pointer events: once the pointer has moved 6 pixels sideways it decides whether the gesture is horizontal (then it takes the pointer capture and the row follows the finger, only to the left) or vertical (then it leaves it to the page, which scrolls: touch-action pan-y). Let go past SWIPE of its width it leaves to the left and its height goes to zero; otherwise it comes back with back.out.

The suggestion, the keys and the preview

The suggestion’s drawing is copied into an element that flies to the new row, whose position is read again every frame because it is opening meanwhile: across with power2.inOut, down with back.in, so it makes an arc; once there, the real drawing bounces. The rows are reached with Tab and Delete takes them away, handing the focus to the first row left; a click from a script (the library’s preview) is a pretend shopper: one more oil, the jam, the jam dragged away, one oil less.

Values to change

NameFileDefaultWhat it changes
FREEscript.js45The total from which delivery is free, in euros.
ITEMSscript.js[['Chestnut honey', 'Jar · 250 g', 9, 1, 'honey'], …]The products in the basket: name, size, price, how many and drawing (honey, oil, pasta or jam).
EXTRAscript.js['Fig jam', 'Jar · 220 g', 6, 1, 'jam']The product suggested, written the same way.
SWIPEscript.js0.4How far a row must be dragged to go, as a share of its width.
FILLscript.js0.9The seconds the bar takes to reach its new length, and the van to drive to the end.

Try them in the Playground

When to use it

For the basket of an online shop or a farm shop, a restaurant order, a fundraiser with a target, any list with a total and a threshold to reach (free shipping, a discount, a gift).

On phones

The rows are dragged to the left with a finger; vertically the page scrolls as usual (touch-action pan-y), because the gesture is taken only when it is clearly sideways; taps on the buttons do not wait for a double tap (touch-action manipulation).

With reduced motion

The figures change without rolling, the prices and the subtotal go straight to the new figure, the bar changes length at once and the van does not drive (it sits on the tip of the bar), rows disappear at once and the suggestion comes in without flying; no entrance.

Pitfalls

  • A subtotal counting with an elastic ease goes past the real figure and shows a wrong price for a moment: the money counts with an ease that does not overshoot, only the bar bounces.
  • A row taken away while it has the focus takes it along and the focus ends up on the page: it must be moved before the row goes, with reduced motion too.
  • With touch-action none the page no longer scrolls over the rows; with pan-y it scrolls vertically and the sideways drag stays with the script, which takes the pointer capture only once the gesture is clearly sideways.
  • The flying drawing must chase the new row, which is opening and moving: its position has to be read again every frame, not only at the start.
  • A red background left under a row at rest, with the same rounded corners, bleeds through the edges as a thin red line (Safari shows it clearly): the red is switched on only while the row is dragged or going.

Libraries

GSAP 3.15.0, Nunito Sans (font variabile) 5.3.0.

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

Testing

Tested on 3 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