
The droplet menu
Menus, SVG, Transitions
Free
The button of a signup that goes through every state of a send: on a press the label leaves and the paper plane takes off, the pill shrinks into a circle with a spinning ring, then a green tick that draws itself, or a red cross and a shake of the head, and a pill again.
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 send button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/dm-sans@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<div class="signup-box" data-box>
<!-- the form: the button goes through its states (sending, sent, failed) and says each one out loud too -->
<form class="signup" data-form novalidate>
<label class="field">
<span class="sr">Your email address</span>
<input class="field__input" type="email" name="email" value="ada@example.com" autocomplete="email" placeholder="you@example.com" aria-describedby="stato" data-email required>
</label>
<div class="send-slot" data-slot>
<button class="send" type="submit" data-send data-autoclic>
<span class="send__halo" data-halo aria-hidden="true"></span>
<span class="send__label" data-label>Subscribe</span>
<svg class="send__plane" data-plane viewBox="0 0 24 24" aria-hidden="true"><path d="M21 3 10.5 13.5M21 3l-6.5 18-4-7.5L3 10z"/></svg>
<svg class="send__state" data-state viewBox="0 0 48 48" aria-hidden="true">
<circle class="send__track" data-track cx="24" cy="24" r="17"/>
<circle class="send__arc" data-arc cx="24" cy="24" r="17"/>
<path class="send__tick" data-tick d="M15.5 24.5l6 6 11-12.5"/>
<path class="send__cross" data-cross d="M17.5 17.5l13 13M30.5 17.5l-13 13"/>
</svg>
</button>
</div>
</form>
<p class="status" id="stato" role="status" aria-live="polite" data-status>No spam. Leave with one click.</p>
<!-- for the demo: the next send fails, to see the other answer -->
<label class="fail">
<input type="checkbox" data-fail>
<span class="fail__box" aria-hidden="true"><svg viewBox="0 0 16 16"><path d="M3.5 8.5l3 3 6-7"/></svg></span>
<span>Make the next send fail</span>
</label>
</div>
</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.
18 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 send button” from Animorio and fit it into my siteThe button sits in a slot as wide as its widest pill: once the fonts have loaded the script measures it with every word the button will say (Subscribe, Try again, Sending, Sent, Not sent) and writes the width into a CSS variable. So while the pill shrinks into a circle and opens again with another word, the field next to it never moves. On a phone the button is as wide as the form and there is nothing to measure.
The label rises 18 pixels and vanishes in 0.26 seconds. The plane crouches and turns its nose by 32 degrees in 0.14 seconds, then flies for FLIGHT seconds with three tweens at once: 112 pixels right with power2.in, 84 up with power4.in, and the rotation to −14 degrees as it shrinks. The two different curves make the path: the climb starts later and grows faster, so first comes the run and then the flight.
The button’s width goes to its height in SHRINK seconds with power3.inOut, and with corners rounded at 999px the pill becomes a circle. Inside there is an SVG with two circles, the track and the arc: the arc is a single dash, it turns with an endless tween and meanwhile its stroke-dashoffset goes back and forth, so it grows and shrinks.
The fake send, fakeSend, is a Promise that resolves after LOADING seconds; in a real form it becomes the fetch to the newsletter service. The mark waits for both the answer and the end of the circle, with Promise.all. The arc closes as its stroke-dashoffset goes to zero, the colour changes and the tick, or the cross, draws itself: it is a dash as long as the line (getTotalLength), pushed out of sight and brought back to zero. A yes swells the button to POP and sends out a green ring; a no shakes it with SHAKE, swings each smaller than the one before.
After HOLD seconds the mark goes and the pill opens again. The script puts in the new word, reads the button’s natural width with no width set, puts it back and animates to it; at the end it removes it (clearProps), so the button follows the CSS again. The word rises into place and a new plane arrives from the bottom left.
Every state is also said in words, in a paragraph with role="status" that screen readers read by themselves. While sending, the button has aria-disabled and a label with the state, the field is read-only and a second click starts nothing. A wrong address gets aria-invalid, the message says what is missing and goes back to normal as soon as you type.
| Name | File | Default | What it changes |
|---|---|---|---|
LOADING | script.js | 1.4 | The seconds the fake send takes (a real one takes what it takes). |
SHRINK | script.js | 0.5 | The seconds of the pill turning into a circle, and back. |
HOLD | script.js | 2.4 | The seconds the answer stays on the button before it becomes a pill again. |
SHAKE | script.js | [10, 3] | The shake of a no: how far it goes, in pixels, and how many times. |
FLIGHT | script.js | 0.8 | The seconds of the paper plane’s flight. |
POP | script.js | 1.12 | How much the button swells for a moment on a yes. |
For a form with a single action that involves a wait: subscribing, sending a message, saving, booking. It works well when the answer comes in a second or two; for longer waits you need a bar that tells how far along it is.
The field and the button stack one under the other and the button is as wide as the form: the wide pill shrinks into a circle in the middle and then opens back out to the edges. The rest is the same, and a tap is the press.
The button does not change shape and nothing flies or shakes: the label changes with a fade (Sending, Sent or Not sent), the fill turns green or red and then dark again, and the line under the field says every state as always.
GSAP 3.15.0, DM Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.2 KB; the libraries: GSAP 28 KB.
Tested on 2 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.