
The needle gauge
Counters, Physics, SVG
NewFree
The bottom bar of a home workout app: the chosen tab stands up like a peg with an orange elastic cord round it. Choosing another, the cord is pulled over there, hooked on the new peg and let go off the old one: it snaps across, tightens round it and wobbles, and the icons feel the tug.
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 rubber band tab bar</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/funnel-sans@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the tab bar of a home workout app. The tab you are on stands up from the bar like a peg, with a rubber band
round it. Choosing another tab, the band is pulled across the bar, hooked round the new peg and let go off
the old one: it snaps over and wobbles. The band is a ring of springs worked out on every frame and drawn
in the canvas over the tabs; the pegs and the icons below feel it -->
<nav class="bar" aria-label="Main" data-bar>
<button class="tab" type="button" data-tab="train" data-autoclic>
<span class="tab__cap" data-cap>
<span class="tab__peg" aria-hidden="true" data-peg></span>
<svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true">
<g data-part="bell"><path d="M7.7 12C6.5 9.4 7.2 5 12 5s5.5 4.4 4.3 7"/><path d="M8.6 20.6a6.2 6.2 0 1 1 6.8 0z"/></g>
</svg>
</span>
<span class="tab__label">Train</span>
</button>
<button class="tab" type="button" data-tab="timer">
<span class="tab__cap" data-cap>
<span class="tab__peg" aria-hidden="true" data-peg></span>
<svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 6.5a7 7 0 1 0 0 14a7 7 0 1 0 0-14zM10 3.4h4M12 3.4v3.1M17.6 7.4l1.3-1.3"/>
<path d="M12 13.5V10" data-part="hand"/>
</svg>
</span>
<span class="tab__label">Timer</span>
</button>
<button class="tab" type="button" data-tab="today">
<span class="tab__cap" data-cap>
<span class="tab__peg" aria-hidden="true" data-peg></span>
<svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true">
<defs><clipPath id="sky"><rect x="0" y="0" width="24" height="16.4"/></clipPath></defs>
<g clip-path="url(#sky)"><g data-part="sun"><path d="M7 17a5 5 0 0 1 10 0"/><path d="M12 7.6V9.4M6.2 10.4l1.25 1.25M17.8 10.4l-1.25 1.25"/></g></g>
<path d="M3.5 17h17M8.5 20.2h7"/>
</svg>
</span>
<span class="tab__label">Today</span>
</button>
<button class="tab" type="button" data-tab="stats" data-autoclic>
<span class="tab__cap" data-cap>
<span class="tab__peg" aria-hidden="true" data-peg></span>
<svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M6.5 19.5v-5" data-part="bar"/><path d="M12 19.5v-9" data-part="bar"/><path d="M17.5 19.5v-14" data-part="bar"/>
</svg>
</span>
<span class="tab__label">Stats</span>
</button>
<button class="tab" type="button" data-tab="you" data-autoclic>
<span class="tab__cap" data-cap>
<span class="tab__peg" aria-hidden="true" data-peg></span>
<svg class="tab__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 4.6a3.6 3.6 0 1 0 0 7.2a3.6 3.6 0 1 0 0-7.2z" data-part="head"/>
<path d="M5 20c.8-3.6 3.6-5.6 7-5.6s6.2 2 7 5.6"/>
</svg>
</span>
<span class="tab__label">You</span>
</button>
<canvas class="bar__band" aria-hidden="true" data-band></canvas>
</nav>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>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.
22 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The rubber band tab bar” from Animorio and fit it into my siteThe cord is a closed ring of 144 points tied by springs, plus a bending stiffness (the fourth difference of the positions) that rounds its bends without lifting it off the peg's corners. A second damping, on the fourth difference of the speeds, only kills tight wrinkles: after the snap the rubber wobbles but does not crumple. The sums are done in steps of half a millisecond, with the frame step capped at 1/30 of a second.
The pegs that stand up are rounded boxes: a point that gets inside is put back on the edge and loses the speed that took it in. The sum of those speeds, divided by the time, is the cord's force on the peg: the peg shifts and leans with it on a spring of its own, a few pixels at most. The hand is the point of the cord facing the new tab most: a GSAP tween carries it past the tab, and within each frame it moves a little at every step of the sums.
When the new peg stands up, the two strands of the drop pass it almost on its middle line: pushed point by point, they would be put out sideways and one strand would stay across the peg. So, while it rises, each point is only pushed out on its own side: over the top for one half of the cord (from the hand onwards), under the bottom for the other. Then the hand lets go, the old peg drops and the tension does the rest.
Each piece of the cord is drawn thinner and paler the more it is stretched from rest, like real rubber. The slanted stripes of the sheath sit on the cord's own points, so they spread apart where it stretches; the metal clasp sits on the first point and turns with it. To keep it cheap the pieces are grouped by colour and thickness: each group is one path, and at rest the whole cord is three.
When no point moves any more, the hand is free and the springs of the pegs and the icons are still, the loop stops working and drawing until something happens (a click, the mouse, a finger). The tabs are buttons in a nav, the chosen one has aria-current; the arrows, Home and End move the focus, Enter and Space choose. The library's preview clicks Train, Stats and You in turn: they have data-autoclic.
| Name | File | Default | What it changes |
|---|---|---|---|
START | script.js | 2 | The tab chosen when the page opens (0 is the first, 2 the middle one). |
PULL | script.js | 0.24 | The seconds it takes to pull the cord to the next tab (a little more to a far one). |
TENSION | script.js | 1 | How hard the rubber pulls back: more, a faster and sharper snap. |
SNUG | script.js | 0.78 | How long the cord is at rest, against the peg it hugs: less, a tighter cord. |
WOBBLE | script.js | 0.55 | How long the cord wobbles after a snap (0 stops at once, 1 very lively). |
THICK | script.js | 4.6 | The thickness of the cord, in pixels. |
PALE | script.js | 0.8 | How pale the rubber goes where it is stretched hard. |
LEAN | script.js | 1 | How far the cord leans towards the tab under the pointer (0 not at all). |
For the navigation bar of an app made for phones, with four or five sections, when changing section can be a little playful: a workout app, an app for children, a creative tool. Even standing still, the cord round the peg says at once where you are.
The bar is at most 420 pixels wide and on a phone narrows to the screen, with a 16 pixel margin each side (358 on a 390 phone); it stays 70 tall and each tab is a 68 by 70 pixel target. With a finger down on a tab the cord leans towards it, as with the mouse over it; from the chosen peg the cord can be taken and dragged with a finger.
The cord does not stretch or snap: it fades off the old peg and back in already tight round the new one, while the pegs fade in and out without rising. No entrance, no icon moves, no plucking and no dragging.
GSAP 3.15.0, Funnel Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP 28 KB.
Tested on 5 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.