Copy to Clipboard
Copy-to-clipboard button with visual confirmation: the copy icon gives way to a green checkmark for 2 seconds, driven by a JavaScript-toggled CSS class.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →
3 usage examples



How it works
The .fx-0369-root frame can appear as many times as needed on the same page: the script finds each instance with document.querySelectorAll('.fx-0369-root') and scopes its buttons inside. No global id is used; two code blocks side by side work independently.
When .mi-copy-btn is clicked, the script reads the content of .mi-copy-code (the visible text in the block) and copies it to the clipboard. On a secure context (HTTPS or localhost), it uses navigator.clipboard.writeText(). On HTTP, it falls back to document.execCommand('copy'). If both fail — clipboard denied, non-secure context without fallback — no confirmation is shown: the checkmark only appears when the copy actually succeeded.
The confirmation is driven by the CSS class .copied added to the root: the copy icon, the check icon and the "Copied!" tooltip are all controlled by CSS transitions (opacity, transform), with no DOM manipulation. The class is removed after 2 seconds via setTimeout. Under prefers-reduced-motion: reduce, all transitions are suppressed; the checkmark appears and disappears without animation.
Accessibility
- Reduced motion: under
prefers-reduced-motion: reduce, CSS transitions are cancelled (transition: none !important); the green checkmark appears without animation and stays 2 s before disappearing instantly. - Keyboard focus:
.mi-copy-btnis a native<button>element, reachable by Tab then Enter or Space. It carriesaria-label="Copy"readable by screen readers. The:focus-visibleoutline is visible. - Confirmation announcement: the tooltip carries
role="status" aria-live="polite"; when the text "Copied!" is written there, screen readers announce it without interrupting the current reading. - Secure context: the
navigator.clipboardAPI is only available over HTTPS orlocalhost. On HTTP, theexecCommandfallback is attempted. If both methods fail, a "Failed" message is shown in the tooltip (aria-live="polite") — never "Copied!" if nothing was copied.
Browser compatibility
CSS transitions + 1.2 KB of JavaScript, no dependency. The navigator.clipboard API is available since Chrome 66, Firefox 63 and Safari 13.1 on a secure context (HTTPS). The execCommand('copy') fallback covers older browsers but is deprecated since Chrome 117 and absent from Safari 17+. Measured in Chromium 151, Firefox 153 and WebKit 26: visual confirmation and voice announcement correct in all three.
Without JavaScript, the button renders but copies nothing and shows no confirmation. On HTTP (outside localhost), the execCommand fallback is attempted; if it fails, no confirmation is shown — the button silently does nothing. On browsers that block clipboard access without an explicit permission, the behavior is the same.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0369-root">
<div class="mi-copy-scene">
<div class="mi-copy-box">
<span class="mi-copy-code">Your text to copy</span>
<button class="mi-copy-btn" aria-label="Copy">
<span class="mi-copy-icon-copy" aria-hidden="true"><!-- copy SVG --></span>
<span class="mi-copy-icon-check" aria-hidden="true"><!-- check SVG --></span>
<span role="status" aria-live="polite" class="mi-tooltip">Copied!</span>
</button>
</div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Text to copy (HTML — content of .mi-copy-code) |
"npm install effect.labs" | Replace with any string; the script reads textContent at click time. You can also set this span's content via JavaScript before injecting the effect into the page. |
Confirmation duration (JS — setTimeout(..., 2000)) |
2000 ms | Lower to 1200 ms for a quick response, raise to 3000 ms to give the user time to read the tooltip. |
Confirmation color (CSS — .fx-0369-root.copied .mi-copy-btn) |
#4ade80 (green) |
Replace with your brand's primary color. The value applies to the check icon and the button border at confirmation time. |
Tooltip text (HTML — .mi-tooltip) |
"Copied!" | Replace with "Link copied", "Code copied" or any contextual label. The content is announced by screen readers via aria-live. |
Text visibility (CSS — .mi-copy-code) |
visible text | Add display: none to hide the text and show only the button (use case: copy button on an icon or image). |
FAQ
navigator.clipboard API is only available over HTTPS (or localhost). On HTTP, the script tries the execCommand('copy') fallback, deprecated since Chrome 117 and absent from Safari 17+. To make copying work everywhere, move your site to HTTPS — which is recommended anyway for security.root.querySelector('.mi-copy-code').textContent at click time. If you want to copy a different value (URL, token, full untruncated ID), store it in data-copy on .mi-copy-code and change the script to read el.dataset.copy || el.textContent..fx-0369-root instance. For multiple buttons in the same block, duplicate the root as many times as needed — each instance is independent — or adapt the script to loop over several .mi-copy-btn elements inside a single root.