
The elastic button
Buttons, Hover, Text
NewFree
A language switcher in the minimal style: five codes in a row, a pale pill behind the one chosen and above them the greeting, large, in that language, Hello, Ciao, Bonjour, Hallo, Hola. Changing language, the letters of the old greeting tip over backwards one after the other, the word changes width and the new letters stand up from the line on a small bounce; the pill stretches over both codes and then lets go of the old one.
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 language switcher that rewrites the greeting</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/mona-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the language switcher of a language app, in the minimal style: five real radio buttons, and above them the
greeting in the language chosen. Choosing another language, the letters of the old greeting tip over
backwards one after the other, the word changes width, and the new letters stand up from the line -->
<form class="lang" data-lang onsubmit="return false">
<p class="lang__brand" aria-hidden="true">Parlo <span>Language</span></p>
<div class="lang__word" aria-hidden="true" data-word>
<span class="lang__letters" data-letters></span>
<span class="lang__shadow" data-shadow></span>
</div>
<p class="lang__name" aria-hidden="true" data-name></p>
<fieldset class="lang__set" data-set data-autoclic>
<legend class="lang__legend">Language</legend>
<div class="lang__row" data-row>
<span class="lang__pill" aria-hidden="true" data-pill></span>
</div>
</fieldset>
<p class="lang__status" aria-live="polite" data-status></p>
</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>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.
30 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 language switcher that rewrites the greeting” from Animorio and fit it into my siteEvery language in the LANGUAGES list becomes a label holding a real, transparent radio button and its code: the arrow keys move from one language to the next as in any radio group, a screen reader reads the name of the language (aria-label) and an aria-live region says “Italiano selected”. The change starts from the radio’s change event, so keyboard, mouse and finger do the same thing.
On every choice the script makes a new line with the greeting, one inline-block box per letter, centred with xPercent −50 inside a holder as wide as the word. The old line stays until its letters have fallen, then it goes: so the two words cross without jumping.
The letters have their transform origin at the bottom centre and the holder a 600-pixel perspective. The old ones go from rotationX 0 to 92 degrees with power2.in, fading, the new ones from −92 to 0 with back.out(BOUNCE), which takes them a little too far; the stagger starts from the side the choice comes from (from start or from end) and the new ones start when the old ones are halfway. At the end the line drops by one pixel and comes back, the settle.
The holder goes from the old word’s width to the new one’s, measured with offsetWidth as soon as the new line exists, in 0.6 seconds with power3.inOut. The shadow is a blurred ellipse at its sides: during the change it narrows to 90 per cent and pales, and comes back when the new letters are up.
The pill behind the code chosen is a single one: first it stretches to cover both the old code and the new one, in 0.2 seconds, then lets go of the old one with elastic.out and settles on the new one. Its measures are the label’s offsetLeft and offsetWidth, taken again on resize. A click from a script on the row (the library’s preview) picks the next language.
| Name | File | Default | What it changes |
|---|---|---|---|
LANGUAGES | script.js | [['EN', 'Hello', 'English'], ['IT', 'Ciao', 'Italiano'], …] | The languages: the code, the greeting and the name of the language written in the language itself. |
START | script.js | 0 | The language chosen when the page opens. |
TIP | script.js | 0.42 | How long a letter takes to tip over or stand up, in seconds. |
STAGGER | script.js | 0.05 | The gap between one letter and the next, in seconds. |
WIDTH | script.js | 104 | The width of the greeting’s face (wdth axis, 75 to 125). |
WEIGHT | script.js | 640 | The weight of the greeting (200 to 900). |
BOUNCE | script.js | 1.7 | How far the letters overshoot standing up (0 no bounce). |
In the header or footer of a site in several languages, in the app of a language school or a dictionary, on the first screen of an app that asks for the language, on the site of a hotel or a museum that speaks to visitors from many countries: wherever changing language should be a gesture you can see.
The same animation with the sizes adapted: the greeting is measured on both the width and the height of the screen (a min of vw and vh), so even Bonjour fits the box; the codes have tighter padding. A tap picks the language and squashes the code pressed.
Nothing tips over or travels: the new greeting fades in where the old one was, the pill reappears on the new code and the name of the language changes with a fade.
GSAP 3.15.0, Mona Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 5.1 KB; the libraries: GSAP 28 KB.
Tested on 24 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.