Skip to content
animorio
IT
All components

The size picker

Pickers, Text, PhysicsGSAPMediumCompressed weight: Demo 8.6 KBGSAP 28 KBFreeDownload the zip

A size picker in the minimal style where the width of the letters is the size: XS narrow, XL wide, on the wdth axis of a variable face. The size chosen widens a little more and takes weight while a hairline vermilion frame catches up with it on two springs, one side after the other; underneath, the measures change word by word and a sold-out size is struck through by a line that draws itself.

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 size picker</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/anybody@5.3.0/wdth.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the size picker of a clothes shop, in the minimal style: five real radio buttons, XS to XL, where the width of
         the letters is the size. Each size is set on the width axis of a variable face, from condensed to extended;
         the one chosen widens a little more and takes weight while a hairline frame catches up with it on two springs,
         one per side. The line under it says the measures and changes word by word. A sold-out size is struck through
         by a thin line that draws itself. The frame, the strike and the ruler are one SVG drawn by the script -->
    <form class="size" data-size onsubmit="return false">
      <fieldset class="size__set" data-set data-autoclic>
        <legend class="size__legend">Size</legend>
        <p class="size__head" aria-hidden="true" data-head></p>
        <div class="size__row" data-row>
          <svg class="size__lines" aria-hidden="true" data-lines>
            <path class="size__ruler" data-ruler/>
            <path class="size__strike" pathLength="1" data-strike/>
            <path class="size__frame" pathLength="1" data-frame/>
          </svg>
        </div>
        <p class="size__line" aria-hidden="true" data-line></p>
        <p class="size__status" aria-live="polite" data-status></p>
      </fieldset>
    </form>
  </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.

41 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 size picker” from Animorio and fit it into my site

What it does

On a white background, at the top a small grey line, “Size · Medium”; below it the five sizes XS, S, M, L and XL in a variable grotesque, each as wide as it is big: XS very narrow, almost compressed, XL stretched out and wide. The size chosen is black and heavy, inside a hairline vermilion frame; the others are light. XS is sold out: pale grey, with a thin line across it from corner to corner. Under the sizes a hairline ruler marks with a tick where every cell begins and ends, and under that a line gives the measures: “Chest 96 cm · Length 70 cm · Fits true to size”. Choosing another size, the old one goes light and narrow again, the new one widens and takes weight, going a little too far and back, and the frame catches up with it on two springs: the side it is heading for leaves first, the other follows, and the frame thins by a pixel as it stretches. The sizes next to it move over to make room, and so does the ruler. In the line underneath only the words that change (the figures) change, letter by letter, from below if the size grows and from above if it shrinks; above, the size’s name does the same. Pointing at XS, or tapping it, the line through it rubs out and draws itself again and the line says “XS is sold out · back in stock soon”.

How it works

The width is the size

The sizes are set in Anybody, a variable face whose wdth axis goes from 50 (extra compressed) to 150 (extra expanded). The script gives every size a value along the scale, from NARROW for the smallest to WIDE for the largest, and writes it in font-variation-settings together with the weight: so the row itself says how big each size is. Choosing adds GROW to the width and goes from LIGHT to BOLD, one step too far and back with elastic.out.

A frame chasing a moving target

While the letters change width the cells change size and move: the script measures the chosen cell on every frame (offsetLeft and offsetWidth) and the frame gets there on two damped springs, one per side, integrated in steps of 1/240 of a second with the time step capped at 1/30. The side it is heading for has the quicker spring, the other is 36 per cent slower: the frame stretches and then closes up, and a damping SPRING[1] under 1 gives the one-pixel overshoot. Stretched wider than its cell it thins by a few tenths of a pixel, like a rubber band.

One SVG for frame, strike and ruler

The frame, the strike of the sold-out size and the ruler are three paths of one SVG over the row, redrawn from the cells’ measures. Frame and strike have pathLength 1 and stroke-dasharray 1 1, so they draw themselves with a single number (stroke-dashoffset from 1 to 0) whatever their length. The loop runs on GSAP’s ticker only while something moves: once the springs are still and no tween is running it takes itself off.

Only the words that change move

The two lines of text are made of slots, one per word, as wide as the word. On a change the words are compared one by one: the same ones stay still, in the others the old letters leave one after the other and the new ones come in with back.out, from below if the size grows and from above if it shrinks, while the slot changes width with power3.inOut. The words start 30 milliseconds apart.

Real radio buttons and the sold-out size

Under every size there is a real radio button: the arrow keys move from one size to the next and the sold-out one, with its radio disabled, is skipped by itself; a screen reader reads “Extra small, sold out” and an aria-live region says the measures. The disabled radio does not hear the pointer (pointer-events: none), so its label can notice the pointer or a tap and have the strike drawn again. A click from a script on the row (the library’s preview) takes one step of a tour: a size up, a size down, the sold-out one, the largest and back to M.

Values to change

NameFileDefaultWhat it changes
SIZESscript.js[['XS', 'Extra small', 84, 66, false], ['S', 'Small', 90, 68, true], …]The sizes: letters, name, chest and length in cm, and whether it is in stock.
STARTscript.js2The size chosen when the page opens (if it is sold out, the first one in stock).
NARROWscript.js54The width (wdth axis) of the smallest size: 50 is the narrowest.
WIDEscript.js136The width of the largest size: 150 is the widest.
GROWscript.js12How much wider the letters of the size chosen get.
LIGHTscript.js300The weight of the sizes not chosen (100 to 900).
BOLDscript.js760The weight of the size chosen.
SPRINGscript.js[24, 0.78]The frame’s springs: how quick and how damped (under 1 they go a hair too far and come back).
FITscript.js'Fits true to size'The end of the line of measures.

Try them in the Playground

When to use it

On a garment’s page in a clothes shop (T-shirts, jumpers, jackets, shoes sized in letters), in the order form for the T-shirts of an event or a team, in the configurator of a product that comes in several sizes: wherever the size chosen must show at once and the measures must change with it.

On phones

The same animation with the sizes adapted: the script measures the row and shrinks the type just enough for it to fit the screen with every size, frame and ruler included. A touch stands in for hover: pressing a size its letters widen a little and squash, letting go they come back. Tapping the sold-out size the strike draws itself again and the line says so for a couple of seconds.

With reduced motion

Nothing moves across: the sizes fade in already in place, choosing one its width and weight change at once, the frame fades out and back in round the new one without travelling, and the words of the line change with a fade instead of rolling.

Pitfalls

  • The frame cannot head for a measure taken on the click: while the new size widens and the old one narrows, every cell moves. The springs chase the cell measured again on every frame, so the frame lands right even halfway through a change.
  • The first face tried, Roboto Flex, with Fontsource’s wdth.css file barely changed width (from 141 to 177 pixels for “XS M XL”): the sizes all looked the same. With Anybody the same line goes from 43 to 257 pixels and the difference shows at a glance.
  • A disabled radio gets no clicks and Playwright refuses to click its label: with pointer-events: none on the sold-out radio the pointer reaches the label, which can react without the size being chosen.
  • Words coming into a slot that widens from nothing squash into each other: the first time, the slots get their width at once and only the letters roll in.

Libraries

GSAP 3.15.0, Anybody (font variabile) 5.3.0.

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

Testing

Tested on 16 October 2026

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

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