Skip to content
animorio
IT
All components

The language switcher that rewrites the greeting

Pickers, Text, HoverGSAP, CSS onlyMediumCompressed weight: Demo 5.1 KBGSAP 28 KBFreeDownload the zip

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.

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 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>

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.

30 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 language switcher that rewrites the greeting” from Animorio and fit it into my site

What it does

On a white background, at the top a small line, “Parlo Language”; under it, large, the greeting in the language chosen, Hello, in a slightly wide variable grotesque, with a soft shadow on the line; under that the name of the language written in the language itself, English, and the row of codes EN, IT, FR, DE, ES inside a hairline frame, with a pale pill behind the one chosen, set in vermilion. Choosing another language, the letters of the old greeting tip over backwards round their base, one after the other, starting from the side the choice comes from; the word widens or narrows to the new one’s size and the shadow tightens for a moment; then the new letters stand up from the line, each one going a little too far and back, and once they are all up the word drops by one pixel and settles. Meanwhile the pill stretches until it covers both the old code and the new one and then lets go of the old one with a bounce, and the name of the language changes with a fade. Pointing at a code it widens and rises by a pixel, pressing it squashes it.

How it works

Real radio buttons, built by the script

Every 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.

One word per line, the letters one by one

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.

Tipping round the base

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 width and the shadow

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 that stretches

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.

Values to change

NameFileDefaultWhat it changes
LANGUAGESscript.js[['EN', 'Hello', 'English'], ['IT', 'Ciao', 'Italiano'], …]The languages: the code, the greeting and the name of the language written in the language itself.
STARTscript.js0The language chosen when the page opens.
TIPscript.js0.42How long a letter takes to tip over or stand up, in seconds.
STAGGERscript.js0.05The gap between one letter and the next, in seconds.
WIDTHscript.js104The width of the greeting’s face (wdth axis, 75 to 125).
WEIGHTscript.js640The weight of the greeting (200 to 900).
BOUNCEscript.js1.7How far the letters overshoot standing up (0 no bounce).

Try them in the Playground

When to use it

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.

On phones

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.

With reduced motion

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.

Pitfalls

  • The words have very different widths (Ciao and Bonjour): the new line must be measured as soon as it exists, before the letters stand up, and the holder changes width by itself; measuring it with the letters turned, offsetWidth is right anyway, because rotations do not change the boxes’ space.
  • Two choices in a row must not leave two lines: before a new choice the running change’s timeline is taken to its end with progress(1), which removes the old line.
  • A space in a two-word greeting must be a non-breaking space (String.fromCharCode(160)), otherwise the empty inline-block box has no width.

Libraries

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.

Testing

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