
The send button
Buttons, Transitions, SVG
NewFree
A lock that opens only if you mean it: held down, an amber colour grows in a circle from where the finger is and the lock's shackle starts to rise, and towards the end the whole button trembles. Let go too soon and the colour runs back; held to the end, the lock springs open and the button turns green. A tap closes it 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 press-and-hold button</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/host-grotesk@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the press-and-hold button: held down, a fill grows out from under the finger and the shackle of the lock starts
to rise; let go too soon and the fill runs back; held to the end, the lock springs open -->
<div class="hold" data-hold data-autoclic>
<span class="hold__ring" aria-hidden="true" data-ring></span>
<button class="hold__btn" type="button" aria-describedby="hold-hint" data-btn>
<span class="hold__face" data-face>
<span class="hold__icon">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path class="hold__shackle" d="M8 11V7.5a4 4 0 0 1 8 0V11" data-shackle/>
<rect x="5" y="11" width="14" height="10" rx="2.6"/>
<path d="M12 14.8v2.6"/>
</svg>
</span>
<span class="hold__label"><span class="hold__word" data-word>Hold to unlock</span></span>
</span>
<span class="hold__face hold__face--fill" aria-hidden="true" data-fill></span>
</button>
<p class="hold__hint" id="hold-hint"><span data-hint>Press and hold until the lock opens</span></p>
<p class="sr" aria-live="polite" data-live></p>
</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.
14 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 press-and-hold button” from Animorio and fit it into my siteThe button has two faces one on top of the other, with the same words and the same lock in the same places: below the graphite one, above the amber copy, which the script makes from the HTML. The copy is cut by a clip-path circle() that grows from the point pressed: where the edge passes, the words change colour halfway through a letter.
While the finger holds, on GSAP's ticker the pressure goes from 0 to 1 in HOLD seconds, and the circle's radius is that fraction of the distance between the point pressed and the button's farthest corner: at 1 it covers it all. The point is measured in the button's own pixels even while SQUEEZE shrinks it.
Past 60% the button moves sideways with two quick waves added together (two sines at different frequencies) and the shackle turns round the foot of its right leg (svgOrigin 16 11), more and more until the end, when the button moves by about SHAKE pixels. Two waves instead of a random number: it shivers without jumping.
Let go early, a tween brings the pressure back to 0 with power2.in, in DRAIN seconds times how full it was, and the circle shrinks back into the point it came from; a new press starts again from there. At 1 the is-open class turns the copy green, the shackle rises and turns 28 degrees with elastic.out, the button returns to its size overshooting it, and a ring widens and fades.
Space and Enter hold it like a finger (the key's repeats are ignored) and the circle grows from the lock. The button has touch-action none and no long-press menu, so the finger does not scroll the page or select. A click from a script (the library's preview) is a pretend hand: once it lets go too soon, the next time it holds to the end, and on the open lock it closes it.
| Name | File | Default | What it changes |
|---|---|---|---|
HOLD | script.js | 1.4 | The seconds to hold before the lock opens. |
DRAIN | script.js | 0.5 | The seconds the colour takes to run back from full, when you let go too soon. |
SQUEEZE | script.js | 0.96 | How small the button gets under the finger. |
SHAKE | script.js | 1.6 | How hard the button trembles just before it opens, in pixels. |
For actions that must not happen by mistake: unlocking a door or a car from an app, confirming a payment or a transfer, deleting something important, signing, starting a recording.
The finger holds the button without scrolling the page, selecting text or opening the long-press menu (touch-action none, user-select none, -webkit-touch-callout none and contextmenu cancelled); the button is 300 pixels wide, or the screen minus 48, and the circle starts where the finger rests.
The colour still grows, because it tells how long is left, but the button does not shrink, tremble or bounce; the lock is open at once without swinging, the ring does not leave, the colour runs back in an instant and the words change without rolling.
GSAP 3.15.0, Host Grotesk (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 5.6 KB; the libraries: GSAP 28 KB.
Tested on 12 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.