1 Pure CSS6 with JSPublished 2026-10-05Free · no sign-up
Seven copy-to-clipboard patterns: a copy button on a code block, a masked key with Show and Copy, a clipboard icon that becomes a tick, a tap-to-copy coupon, a Copied! tooltip, a snippet that selects itself in one click and a link copied as plain text, Markdown or HTML.
A Copy button in the corner of a code block that copies exactly the code text, then shows Copied for two seconds. The button names what it copies, and the confirmation is announced through a status region.
var w = document.querySelector('.cpy1'), b = w.querySelector('button'), st = w.querySelector('.sr');
function fb(t) { var a = document.createElement('textarea'); a.value = t; a.style.position = 'fixed'; a.style.opacity = '0'; document.body.appendChild(a); a.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} a.remove(); return ok; }
function done(ok) { b.classList.toggle('ok', ok); b.textContent = ok ? 'Copied' : 'Select and copy'; st.textContent = ok ? 'Copied' : ''; setTimeout(function () { b.classList.remove('ok'); b.textContent = 'Copy'; }, 2000); }
b.onclick = function () { var t = w.querySelector('code').textContent; if (navigator.clipboard) navigator.clipboard.writeText(t).then(function () { done(true); }, function () { done(fb(t)); }); else done(fb(t)); };
02. Masked API Key with Copy and Reveal
CopyInput
A read-only field holding a key that is masked by default, with Show and Copy buttons beside it. Copy works whether or not the key is visible, the Show button reports its state with aria-pressed, and the key in the demo is fake.
var i = document.getElementById('cpy2k'), sh = document.querySelector('.cpy2 .sh'), cp = document.querySelector('.cpy2 .cp'), st = document.querySelector('.cpy2 .st');
sh.onclick = function () { var show = i.type === 'password'; i.type = show ? 'text' : 'password'; sh.textContent = show ? 'Hide' : 'Show'; sh.setAttribute('aria-pressed', show); };
function fb(t) { var a = document.createElement('textarea'); a.value = t; a.style.position = 'fixed'; a.style.opacity = '0'; document.body.appendChild(a); a.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} a.remove(); return ok; }
cp.onclick = function () { var say = function (ok) { st.textContent = ok ? 'Key copied. Store it somewhere safe.' : 'Copy blocked here. Select the key and press Ctrl+C.'; }; if (navigator.clipboard) navigator.clipboard.writeText(i.value).then(function () { say(true); }, function () { say(fb(i.value)); }); else say(fb(i.value)); };
03. Clipboard Icon Turns into a Tick
CopyIcon
An icon-only copy button whose clipboard icon is swapped for a tick for two seconds after copying. Both icons are in the button and the visible one is chosen by a class, and the button's accessible name changes from Copy to Copied too.
var b = document.querySelector('.cpy3 button'), t = document.querySelector('.cpy3 code').textContent;
function fb() { var a = document.createElement('textarea'); a.value = t; a.style.position = 'fixed'; a.style.opacity = '0'; document.body.appendChild(a); a.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} a.remove(); return ok; }
function done(ok) { if (!ok) return; b.classList.add('ok'); b.setAttribute('aria-label', 'Copied'); setTimeout(function () { b.classList.remove('ok'); b.setAttribute('aria-label', 'Copy order number'); }, 2000); }
b.onclick = function () { if (navigator.clipboard) navigator.clipboard.writeText(t).then(function () { done(true); }, function () { done(fb()); }); else done(fb()); };
04. Copyable Coupon Code
CopyEcommerce
A dashed coupon box where the whole code is a button, so a tap anywhere on it copies the code. The button text reads the code and the action (SPRING20, copy code), and a status message confirms the copy.
View code
<div class="cpy4"><p>20% off your first order</p><button><span class="c">SPRING20</span><span class="a">Tap to copy</span></button><p class="st" role="status"></p></div>
var b = document.querySelector('.cpy4 button'), code = b.querySelector('.c').textContent, a = b.querySelector('.a'), st = document.querySelector('.cpy4 .st');
function fb() { var x = document.createElement('textarea'); x.value = code; x.style.position = 'fixed'; x.style.opacity = '0'; document.body.appendChild(x); x.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} x.remove(); return ok; }
function done(ok) { a.textContent = ok ? 'Copied!' : 'Copy failed'; st.textContent = ok ? 'Code ' + code + ' copied. Paste it at checkout.' : 'Please write down the code ' + code + '.'; setTimeout(function () { a.textContent = 'Tap to copy'; }, 2000); }
b.onclick = function () { if (navigator.clipboard) navigator.clipboard.writeText(code).then(function () { done(true); }, function () { done(fb()); }); else done(fb()); };
05. Copied Tooltip Above the Button
CopyTooltip
A small Copied! bubble pops up above the button and fades away, a confirmation that does not move anything else on the page. The bubble is aria-hidden decoration; the same message is announced by a status region for screen reader users.
var i = document.querySelector('.cpy5 input'), b = document.querySelector('.cpy5 button'), tip = b.querySelector('.tip'), st = document.querySelector('.cpy5 .sr');
function fb() { i.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} return ok; }
function done(ok) { if (!ok) { st.textContent = 'Copy blocked. Select the link and copy it.'; return; } tip.classList.add('on'); st.textContent = 'Link copied'; setTimeout(function () { tip.classList.remove('on'); }, 1500); }
b.onclick = function () { if (navigator.clipboard) navigator.clipboard.writeText(i.value).then(function () { done(true); }, function () { done(fb()); }); else done(fb()); };
06. Click to Select All
CopySelection
Sometimes the best copy button is no button: user-select: all makes a single click select the whole snippet, ready for Ctrl+C. It works everywhere, needs no permissions, and suits short values like a hash or a URL.
View code
<p class="cpy6">Commit: <code>9f3a21c</code> · Click the code once to select it all.</p>
A link can be copied in three formats from a small group of buttons: the plain URL, a Markdown link or an HTML anchor. Each button names its format, and the status line confirms which format went to the clipboard.
var st = document.querySelector('.cpy7 .st'), url = 'https://example.com/notes', title = 'Calm design notes';
var fmt = { url: url, md: '[' + title + '](' + url + ')', html: '<a href="' + url + '">' + title + '</a>' };
function fb(t) { var a = document.createElement('textarea'); a.value = t; a.style.position = 'fixed'; a.style.opacity = '0'; document.body.appendChild(a); a.select(); var ok = false; try { ok = document.execCommand('copy'); } catch (e) {} a.remove(); return ok; }
document.querySelectorAll('.cpy7 button').forEach(function (b) { b.onclick = function () { var t = fmt[b.dataset.f], say = function (ok) { st.textContent = ok ? 'Copied as ' + b.textContent : 'Copy blocked in this frame.'; }; if (navigator.clipboard) navigator.clipboard.writeText(t).then(function () { say(true); }, function () { say(fb(t)); }); else say(fb(t)); }; });
About these CSS Copy Buttons
Clipboard API with a fallback
navigator.clipboard.writeText() is the modern way, but it can be blocked in some frames or contexts. Fall back to selecting a hidden textarea and execCommand('copy'), and if that fails too, tell people to press Ctrl+C.
Confirm the copy
Change the button to Copied for a couple of seconds and announce it through a role="status" region, so everyone knows it worked.
Name what is copied
Copy install command or Copy order number is clearer than a row of identical Copy buttons, especially for screen reader users moving between them.
Sometimes no button is needed
user-select: all makes a short value select itself in one click, which works everywhere with no permissions.
Frequently asked questions
Why does copy fail in some previews?
Sandboxed frames can block clipboard access. The fallbacks in each demo handle that case.
Is it safe to copy secrets?
Copying is fine; just avoid logging the value and mask it on screen by default.
Does copy need HTTPS?
The Clipboard API needs a secure context; the fallback works on HTTP too.