Utilities✨ Premium

Copy to Clipboard

Read-only field and Copy button: green check and "Copied!" when the copy works, a visible message and selected text when the browser refuses it.

JSClickFeedback

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

API keys to copy in the developer settings — Copy to Clipboard example 1

① API keys to copy in the developer settings

WhenIn the Developers tab of a payment tool, the integrator copies the secret key to paste it in their server configuration, then the publishable key for their web page.
WhyThe secret key stays masked on screen (tz_live_••••••7Q4K) while the real value goes to the clipboard: nobody looking over the shoulder reads it, and the developer does not have to select it by hand.
SettingsTwo roots in two cards. First one: data-cpb-text = the real key, masked field, data-cpb-said="Secret key copied". Both: --cpb-font-size: .84rem, --cpb-field-width: 198px, demo frame set to zero. In the capture, the scene calls root.fx0739.copy() every 2.6 s and lends the capture browser a clipboard that accepts the copy (it has none).
Wi-Fi password on a coworking welcome tablet — Copy to Clipboard example 2

② Wi-Fi password on a coworking welcome tablet

WhenThe visitor arrives, reads the network name and the password in large type on the tablet at reception, and taps Copy on their phone showing the same page.
WhyLarge text reads from a distance, the button is easy to hit with a finger, and the green check confirms without a sentence: they can open the Wi-Fi settings and paste.
Settings--cpb-font-size: 1.4rem (everything scales with it), --cpb-field-width: 268px; darker field background and golden border from the scene's CSS. Copy repeated every 2.5 s in the capture, with the same lent clipboard.
Video call link in a calendar row — Copy to Clipboard example 3

③ Video call link in a calendar row

WhenIn the week's calendar, the 2 pm meeting is expanded: its video link shows with a small Copy button at the end of the row, ready to paste into an invitation.
WhyAt a small size, the effect fits in a list row; the green button and the check mark are enough feedback, with no popup or banner covering the calendar.
Settings--cpb-font-size: .75rem, --cpb-field-width: 236px, data-cpb-said="Meeting link copied". Copy repeated every 2.5 s in the capture.

How it works

On click, the script copies the value of the .cpb-input field, or the text of data-cpb-text if it is set on the root: the field can then show a masked key while the real one goes to the clipboard. It first uses navigator.clipboard.writeText, available on a page served over https or localhost.

If that API is missing (http page) or the browser refuses, a fallback copies with document.execCommand('copy') through a hidden field, then gives focus back where it was. If the fallback fails too, nothing is hidden: the real text is put in the field, selected, and the data-cpb-fail message shows in amber under the row, asking to copy with the keyboard.

When the copy works, the button turns to a green gradient, the copy icon gives way to a bouncing check mark (0.4 s) and the label becomes data-cpb-done for data-cpb-reset milliseconds (2000 by default). The check mark sits where the icon was: the button keeps its width. The field is 260 px wide (--cpb-field-width), shrinks on a narrow screen and moves above the button when space runs out.

Each .fx-0739-root is a separate instance. The fx0739:copy event (detail.ok, detail.text) leaves the root on every try, and root.fx0739.copy() starts a copy from your code.

Accessibility

  • Announcement: the .cpb-msg area (role="status") reads "Copied to clipboard" on success, and the failure message when copying is refused. Without it, a screen reader user would not know whether the click did anything.
  • Named field: the field has an aria-label ("Command to copy"); adapt it to what it holds. Read-only, it can still be reached with the keyboard and selected by hand.
  • Keyboard: real <button>, Enter and Space; lavender ring on keyboard focus on the field and the button. On failure, focus moves to the field with the text selected, ready for Ctrl+C.
  • Contrast: white text on the indigo gradient #5a5df0 → #8453f5: 4.6 to 4.9:1; on the green of "Copied!", #0c855d → #036043: 4.6:1 and above. Measured in Chromium, Firefox and WebKit, at rest, on hover and after copying. If you change these gradients, keep at least 4.5:1 on their lightest colour.
  • Reduced motion: no lift on hover, no transition and no check mark bounce; the colour and label change remain.

Browser compatibility

Dependency-free JavaScript (3.7 KB comments included) and two SVG icons. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): code pasted twice, each copy copies on its own (text read back from Chromium's clipboard), page without the clipboard API (fallback works), copy fully refused (visible message, text selected), keyboard, touch at 390 px, reduced motion, 0 errors, no name added to window.

Chrome 86+✓ Full (measured)
Firefox 85+✓ Full (measured)
Safari 15.4+✓ Full (measured in WebKit)
Edge 86+✓ Full (Chromium engine)
Mobile iOS 15.4+✓ WebKit engine, not checked on a device
Android Chrome 86+✓ Full (touch measured)

navigator.clipboard.writeText exists since Chrome 66, Firefox 63 and Safari 13.1; before that, the execCommand('copy') fallback (Chrome 42, Firefox 41, Safari 10) takes over. The focus ring needs :focus-visible (Chrome 86, Firefox 85, Safari 15.4). Without JavaScript, the button copies nothing but the field can still be selected.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0739-root" data-cpb-done="Copied!" data-cpb-said="Copied to clipboard" data-cpb-fail="Automatic copy was blocked: the text is selected, copy it with Ctrl+C (⌘+C on Mac).">
  <div class="cpb-demo">
    <input type="text" class="cpb-input" value="npm run build" readonly aria-label="Command to copy">
    <button type="button" class="cpb-btn">
      <svg class="cpb-copy-icon" aria-hidden="true">…</svg>
      <svg class="cpb-check-icon" aria-hidden="true">…</svg>
      <span class="cpb-text">Copy</span>
    </button>
    <p class="cpb-msg" role="status" aria-live="polite"></p>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Copied text (HTML — data-cpb-text on the root) absent: the field's value Copies a different value from the one shown (masked key, full link behind a short label).
Label after copying (HTML — data-cpb-done) "Copied!" Replaces the button text during the copied state.
Announcement (HTML — data-cpb-said) "Copied to clipboard" Sentence read by screen readers; say what was copied.
Failure message (HTML — data-cpb-fail) "Automatic copy was blocked: the text is selected…" Shown in amber under the row and announced when every copy attempt failed.
Copied state duration (HTML — data-cpb-reset) 2000 ms Time before the starting label comes back.
Size (CSS — --cpb-font-size, --cpb-field-width) 1rem · 260 px The font size drives paddings and icons; the field width is set separately.
Frame (CSS — --cpb-height, --cpb-page, --cpb-panel, --cpb-pad) 300 px · #0a0a0f · #1a1a2e · 20 px Set 0 and transparent to put the field and button in your own card.
Code (JS — root.fx0739.copy(), fx0739:copy event) — Starts a copy; the event says whether it worked (detail.ok), for your analytics for instance.

FAQ

Browsers only give navigator.clipboard to secure pages (https or localhost). Over http, the effect tries execCommand('copy'), which still works almost everywhere after a click; otherwise the text is selected and the message asks for Ctrl+C. Moving the site to https settles it.
Yes: so that the visitor can copy it by hand, the data-cpb-text value is then put in the field and selected. If it must never be shown, remove that behaviour in fail() and keep only the message.
Yes, as many as you like: each .fx-0739-root block has its own field, button, timer and announcement. The script can even be pasted twice without copying twice.