Skip to content
animorio
IT
All components

The price range

Sliders, Physics, TransitionsGSAPMediumCompressed weight: Demo 6.5 KBGSAP 28 KBFreeDownload the zip

A filter for the price of a night over a histogram of the stays: the two handles follow the hand on springs, stretching a little, the bars change colour with a little jump as a handle goes over them, the two prices join when they meet and the number of stays counts up and down.

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 price range</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/sofia-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the price range: two handles on springs over a histogram of prices; the bars light up with a little jump as a
         handle goes over them, the two prices join when they meet, and the number of stays counts up and down -->
    <section class="price" aria-labelledby="price-title" data-price data-autoclic>
      <header class="price__head">
        <div>
          <h2 class="price__title" id="price-title">Price per night</h2>
          <p class="price__note">Before taxes and fees</p>
        </div>
        <p class="price__count"><span data-count>0</span> stays</p>
      </header>
      <div class="price__chart" data-chart>
        <div class="price__bars" aria-hidden="true" data-bars></div>
        <div class="price__track" aria-hidden="true"><span class="price__fill" data-fill></span></div>
        <span class="price__thumb" aria-hidden="true" data-thumb></span>
        <span class="price__thumb" aria-hidden="true" data-thumb></span>
        <span class="price__tag" aria-hidden="true" data-tag></span>
        <span class="price__tag" aria-hidden="true" data-tag></span>
        <span class="price__tag price__tag--both" aria-hidden="true" data-both></span>
        <input class="price__range" type="range" aria-label="Minimum price" data-range>
        <input class="price__range" type="range" aria-label="Maximum price" data-range>
      </div>
      <div class="price__fields">
        <label class="field">
          <span class="field__label">Minimum</span>
          <span class="field__box"><span aria-hidden="true">€</span><input class="field__input" type="text" inputmode="numeric" autocomplete="off" data-field></span>
        </label>
        <label class="field">
          <span class="field__label">Maximum</span>
          <span class="field__box"><span aria-hidden="true">€</span><input class="field__input" type="text" inputmode="numeric" autocomplete="off" data-field></span>
        </label>
      </div>
      <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.

24 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 price range” from Animorio and fit it into my site

What it does

On a white background a card with Price per night, Before taxes and fees and, in a teal label, 301 stays; under it, a histogram of 36 bars (how many stays cost how much, from 20 to 380 euros), a line with two round handles and the part between them coloured, the prices chosen in two dark labels (€80 and €220) and two boxes, Minimum and Maximum. When the page opens the bars grow from the bottom one after another and the handles open out from the middle, lighting the bars they go over. Dragging a handle (or pressing on the chart, which takes the nearer one) the handle follows the hand on a spring, stretching a little as it runs; the bars it goes over change colour with a little jump, up for those coming in and down for those leaving, the number of stays goes up or down and the price labels follow; when they touch they become one, like €180 – €220. The handles do not go past each other. A price typed in a box moves its handle; something that is not a price shakes the box, which goes back to what it was.

How it works

Handles on springs

Each handle heads for the price chosen (rounded to STEP) on a spring (SPRING), worked out on GSAP’s ticker in steps of 4 milliseconds; the spring’s speed stretches it (scaleX up to 1.28, and a little thinner). The handles stop a step short of each other, so they never cross.

The bars that jump

Each bar has its own spring (POP) between 0 (out) and 1 (in): it is in when its middle lies between the two handles where they are now, so it changes just as a handle goes over it. The colour goes from grey to teal with the spring; when the spring overshoots (held back little, it jumps) the bar stretches coming in and shrinks going out.

The prices that join

The labels sit under the handles, kept inside the chart; when less than 8 pixels are left between them they make way, fading, for a single label with the lowest and highest price, in the middle between the handles.

The number of stays

The stays’ prices are a fixed set (the same every time, from a seeded generator): the histogram counts them in BARS groups, and the number at the top is how many lie between the two prices chosen, brought to the new value in 0.5 seconds.

Keys and the preview

Under the drawn handles there are two real sliders (range inputs) with aria-valuetext in euros: Tab reaches them, the arrows move by STEP, Page Up and Down by more, Home and End to the ends, and the drawn handle shows the focus. The boxes take a price and confirm it with Enter; an aria-live region says how many stays there are between the two prices. A click from a script (the library’s preview) is a pretend hand that takes the handles to a new range, one after the other.

Values to change

NameFileDefaultWhat it changes
RANGEscript.js[20, 380]The lowest and the highest price on the scale, in euros.
STEPscript.js5How many euros a handle moves by.
SPRINGscript.js[520, 0.72]The handles’ spring: how stiff it is and how much it is held back.
POPscript.js[420, 0.4]The bars’ spring as a handle goes over them: stiff and held back little, so it jumps.
BARSscript.js36How many bars the histogram has.
STARTscript.js[80, 220]The prices chosen when the page opens.

Try them in the Playground

When to use it

For the filters of a booking site, a shop, an estate agent or a listings site: anywhere a range is chosen, of price, of size, of years.

On phones

The chart is dragged with a finger without scrolling the page (touch-action none) and a press anywhere takes the nearer handle; the boxes are 16 pixels, so Safari on iPhone does not zoom the page, and they open the number keyboard (inputmode numeric).

With reduced motion

The handles go straight to the price chosen, without spring or stretch, the bars change colour without jumping, the number changes at once, the labels join without fading and nothing grows when the page opens.

Pitfalls

  • Two range inputs one over the other steal the pointer from each other: here they lie underneath, hidden, only for the keys and screen readers, and dragging is done by the drawn chart.
  • In a grid of two 1fr columns a text box does not shrink below its natural width and sticks out of the card: minmax(0, 1fr) for the columns and width 100% on the input.
  • Number of an empty string is 0, not NaN: a text with no digits must be checked first, or it would become the lowest price.
  • The bars change by where the handles are at that moment, not by the prices chosen: so the wave follows the handle instead of arriving all at once.

Libraries

GSAP 3.15.0, Sofia Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 6.5 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