Skip to content
animorio
IT
All components

The copy button

Buttons, Text, SVG, PhysicsGSAP, CanvasAdvancedCompressed weight: Demo 8.2 KBGSAP 28 KBFreeDownload the zip

An install command with its Copy button: on the click the characters lift one after another and fly in a stream into the clipboard icon, which fills like a glass with a sloshing wave; full, it turns into a tick that draws itself and the label scrambles its letters into Copied. Then the characters drop back into their places. It really copies.

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 copy button</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist-mono@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the snippet: pressed, Copy puts the command on the clipboard while its characters lift one after another, fly
         in a stream into the clipboard icon and fill it like a glass; the icon turns into a tick that draws itself,
         the label scrambles into Copied, and the characters drop back into their places -->
    <figure class="snippet" data-snippet data-autoclic>
      <div class="snippet__row">
        <pre class="snippet__code"><code data-code><span class="tok tok--prompt" aria-hidden="true">$</span> <span data-cmd-text>npm install gsap</span></code></pre>
        <button class="copy" type="button" aria-label="Copy the command" data-copy>
          <svg class="copy__icon" viewBox="0 0 24 24" aria-hidden="true">
            <defs>
              <clipPath id="copy-board"><rect x="5.6" y="5.6" width="12.8" height="15.3" rx="2.2"/></clipPath>
            </defs>
            <g data-board>
              <g clip-path="url(#copy-board)"><path class="copy__liquid" d="" data-liquid/></g>
              <rect class="copy__line" x="5.6" y="5.6" width="12.8" height="15.3" rx="2.2"/>
              <rect class="copy__clip" x="8.6" y="3.4" width="6.8" height="3.6" rx="1.2"/>
            </g>
            <path class="copy__tick" pathLength="1" d="M6.5 12.6l3.6 3.6 7.4-7.6" data-tick/>
          </svg>
          <span class="copy__label" data-label>Copy</span>
        </button>
      </div>
      <p class="sr" aria-live="polite" data-live></p>
    </figure>
  </main>
  <!-- the characters in flight, over the whole page -->
  <div class="flight" aria-hidden="true" data-flight></div>

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

19 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 copy button” from Animorio and fit it into my site

What it does

On a white background a dark code block with the command $ npm install gsap, coloured by parts, and on its right a Copy button with a clipboard icon. With the mouse over it the button brightens and the clipboard's clip lifts a little. Pressing it, the command really goes on the clipboard and its characters, from the first to the last, lift off their places in a wave and fly on a curve into the icon, each in its colours with a thin trail fading behind it. In the icon the green rises like water in a glass: at every character that drops in, the surface tilts and waves. Full, the icon shrinks away, a green tick draws itself in its place and the label goes from Copy to Copied scrambling its letters. A moment later the tick goes, the empty icon comes back and the characters drop back into their places from above, one after another, with a little bounce.

How it works

One character, one element

The command is written by the script one character per span, with the class of its part (the program, the verb, the package) for its colour. On the click each character gets a copy in a fixed layer over the page, put exactly where the original sits, which hides: the copy is what flies, so the real text never moves and stays selectable.

The flight on a curve

Each copy lifts by LIFT pixels, then follows a quadratic Bézier curve from its home to the icon's mouth, with the control point ARC pixels above (never past the block's top edge, where the light background would make it vanish: that is why the command has 48 pixels of dark block above and below it, 44 on a phone) and a little different for each. GSAP moves only a number from 0 to 1 for each character, STAGGER seconds after the one before, with power1.in: a loop on the ticker works out its position, its rotation and its shrinking size.

The trail

Each character keeps the last points it went through (more with a high TRAIL) and a full-screen canvas redraws them every frame as a line that thins and fades towards its tail, in the character's colour. Once it has landed, the trail drains from the tail.

The glass

Inside the icon, cut to its shape by a clipPath, sits an SVG path redrawn every frame: the level rises with each character that arrives, and the surface is a tilted line plus a wave, both on small damped springs. Each character dropping in gives the springs a knock (SLOSH), and the wave calms down by itself; near the bottom and the brim the amplitude narrows so as not to spill.

Copied, and back

Full, the icon shrinks away and a tick draws itself with stroke-dashoffset; the label changes by scrambling: each letter goes through a few random characters before it settles, from the left, and its box widens by one ch per letter (the font is monospaced). After COPIED seconds the characters drop back from 18 pixels above with back.out. The clipboard is written with navigator.clipboard and, if the browser says no, with a hidden textarea and execCommand; if that fails too, the command is selected.

Values to change

NameFileDefaultWhat it changes
STAGGERscript.js0.028The seconds between one character lifting and the next.
FLIGHTscript.js0.55The seconds a character takes to fly into the clipboard.
ARCscript.js48How high the characters arc on their way, in pixels (never past the block's top edge).
LIFTscript.js9How many pixels a character lifts off its place before it flies.
TRAILscript.js0.6How long the trail behind a flying character stays, from 0 to 1.
SLOSHscript.js1How much the liquid sloshes as the characters drop in.
COPIEDscript.js1.6The seconds the button says Copied before the characters go back.

Try them in the Playground

When to use it

For the Copy button next to a short command, an API key, a discount code or an address to paste: wherever copying is the page's main action and worth showing. For long blocks better to fly only the first line: hundreds of characters in flight become a cloud.

On phones

The block narrows to the width of the screen and the command goes down to 13.5 pixels; the command scrolls sideways inside its box if it does not fit, without making the page overflow. A tap works like a click, and the flight is the same, shorter because the button is closer.

With reduced motion

The characters do not fly: the command stays still, the icon gives way to the tick and the label becomes Copied at once, without scrambling; then everything comes back with a fade. The button does not shrink under the press.

Pitfalls

  • Flying the real characters moves the text around them and breaks selection: the copies fly in a fixed layer over the page, measured with getBoundingClientRect, and the original only turns transparent, so it still holds its place.
  • With free curves the program's white characters rose above the block, over the light background, and vanished. The curve's highest point is kept 14 pixels below the block's edge.
  • The trail added a point every frame even when time stood still (the bench's pause): a very long line stayed between two distant positions. A point is added only if the character has moved.
  • Only a real click may write to the clipboard: navigator.clipboard refuses fake clicks and pages without https. The preview's click plays the animation without touching the clipboard, and a refusal from the browser falls back to the hidden textarea and then to the selection.
  • The Copy and Copied labels have different widths: with a free width the button jumped at every scrambled letter. The label's box is as wide as the new word has characters (in ch, the font is monospaced) and gets there with a transition.

Libraries

GSAP 3.15.0, Geist (font variabile) 5.3.0, Geist Mono (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 8.2 KB; the libraries: GSAP 28 KB.

Testing

Tested on 4 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

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