
The copy button
Buttons, Text, SVG, Physics
NewFree
The Delete project button of an app, in the minimal style, that deletes nothing on the first click: the label becomes Click again to delete and the pill stretches on a spring. The time to answer is the room that is left: over three seconds the pill closes in on the question, the letters condense on the width axis to always fit exactly, and a thin vermilion line under them burns down from both ends. If nobody answers, Delete project comes back; on the second click the pill folds down into its line, which becomes the rule under Project deleted, with Undo beside it.
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 button that asks twice</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the frame keeps the room of the widest state, so the preview never has to move -->
<div class="frame" data-frame>
<!-- the pill: drawn by the script on every frame. After the first click it asks again, and the time to answer
is the room it has: the pill closes in on the question, the letters condense on the width axis to stay
inside, and a thin line under them burns down to nothing. Confirmed, the pill folds down into that line -->
<span class="pill" aria-hidden="true" data-pill>
<span class="label" data-rest>Delete project</span>
<span class="label" data-ask>Click again to delete</span>
<span class="fuse" data-fuse></span>
</span>
<button class="del" type="button" aria-label="Delete project" data-del data-autoclic></button>
<!-- once it is done: a quiet note sitting on the line the pill became, and the way back -->
<div class="done" data-done>
<span class="done__clip" aria-hidden="true"><span class="done__text" data-done-text>Project deleted</span></span>
<button class="undo" type="button" aria-label="Undo, restore the project" data-undo>
<span class="undo__clip" aria-hidden="true">
<svg class="undo__arrow" viewBox="0 0 16 16" data-arrow><path d="M5.6 3.8 2.6 6.8l3 3M2.6 6.8h7.1a3.4 3.4 0 0 1 0 6.8H7.2" pathLength="1" data-arrow-path/></svg>
<span class="undo__word" data-undo-word>Undo</span>
</span>
</button>
</div>
</div>
<p class="sr" role="status" aria-live="polite" data-said></p>
</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.
27 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 button that asks twice” from Animorio and fit it into my siteArchivo is a variable typeface with a width axis, from 62 to 125. At the start, once the typeface has arrived (document.fonts.load for both weights), the script measures Delete project and Click again to delete on the real element with getBoundingClientRect, at six widths of the axis and two weights. The width at any axis and weight comes from interpolating between the four nearest values: while the pill moves nothing is measured any more, it is only arithmetic.
The first click starts a GSAP tween that carries one number, the time, from 0 to 1 over WINDOW seconds, with no curve. The time goes through a curve that starts slow and speeds up, and from it come the axis width of the question (from SQUEEZE[0] to SQUEEZE[1]) and its weight (from WEIGHT[0] to WEIGHT[1]); the pill is as long as the question at that axis plus the margin, so it closes in on the sentence and the sentence condenses to fit. The line is as long as the question at that instant times the time left, centred: it burns down from both ends.
The pill has no fixed shape: it is three numbers, its length, its top edge and its bottom edge, each on a damped spring integrated in half steps, with the time step capped at 1/30 of a second. The length follows SPRING, damped just under 1, and goes a pixel past when it stretches; the edges follow FOLD. When the springs come within three hundredths of a pixel they settle exactly on the target, so the pill at rest is always the same picture and the function on the GSAP ticker removes itself.
The counting line sits 14 pixels under the centre, and that is where the pill folds: on the second click its edges go to 14 minus and plus 0.75 pixels and its length becomes that of the row Project deleted · Undo, measured with room for the hover. The labels inside the pill always stay at the centre of the frame whatever the top edge does (the script moves their top the other way), so the edge coming down covers them like a blind. Project deleted and Undo sit in two clips that end just above the rule, and rise out of it.
A second click closer than GUARD seconds to the first is a double click, and confirms nothing: without this check whoever double-clicks out of habit would delete the project. Enter twice does what the mouse does, Escape cancels the question. After the confirmation the focus goes to Undo, and after Undo back to the button. A hidden text with role=status says the question and the time, Deletion cancelled, Project deleted and Project restored.
A click made by a script has detail equal to 0, but so do Enter and the space bar: to tell them apart the script notes the key pressed before the click. A script click with no key behind it starts a GSAP timeline with the whole round: the question left to run out, the question confirmed, Project deleted, Undo and Delete project again. Script clicks arriving during the round do nothing; a real click stops it and the button answers from there.
| Name | File | Default | What it changes |
|---|---|---|---|
LABEL | script.js | 'Delete project' | The label at rest. |
ASK | script.js | 'Click again to delete' | The question after the first click; its last word takes the accent. |
DONE | script.js | 'Project deleted' | The note once it is done, over the rule. |
UNDO | script.js | 'Undo' | The word for going back. |
WINDOW | script.js | 3 | The seconds there are to confirm: the line burns down and the pill closes in over this time. |
GUARD | script.js | 0.35 | A second click closer than this to the first is a double click and does not confirm. |
SQUEEZE | script.js | [100, 64] | The width axis of the question when it is asked and when time is up (Archivo goes from 62 to 125). The further apart, the more the pill closes in. |
WEIGHT | script.js | [560, 690] | The weight of the labels, and the weight the question reaches as it tightens. |
SPRING | script.js | [430, 0.78] | The spring of the pill’s length: stiffness and damping (under 1 it goes a pixel past and comes back). |
FOLD | script.js | [300, 0.8] | The spring of the edges, which folds the pill into the line and opens it up again. |
STAGGER | script.js | 0.016 | The seconds between one letter and the next as a label comes in. |
SWELL | script.js | 6 | The pixels the pill swells under the pointer. |
For any action that must not happen by mistake but does not deserve a confirmation dialog: deleting a project, removing a member from a team, emptying the bin, revoking a key. The second click is in the same spot as the first, so confirming costs a single extra gesture; Undo stays for whoever regrets it anyway.
The pill is the same, 60 high, and the question at full width fits easily in 390 pixels. Without a pointer there is no hover swell: a tap squashes the pill and releases it on the spring; two taps confirm, with the same animations as on a computer, and Undo has a touch area larger than the word.
No letters rising or falling, no springs and no pill closing in: the labels fade into each other, the pill takes the right size at once and the question stays at full width. The time still shows in the vermilion line burning down, because it is information and not decoration. Once confirmed, the pill is a rule at once and the note fades in.
GSAP 3.15.0, Archivo (font variabile, con gli assi del peso e della larghezza) 5.3.0.
Compressed with gzip, the three demo files weigh 9.0 KB; the libraries: GSAP 28 KB.
Tested on 16 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.