Copying to the Clipboard in 2025

Amir YuristaAmir Yurista
2 min read

Copy-to-clipboard helpers feel almost primitive today, yet they still pop up in projects every week. The gist you shared shows the classic pattern that dominated for years:

// Legacy helper
function copyToClipboard(text) {
  const el = document.createElement('textarea');
  el.value = text;                          // put text in a hidden <textarea>
  el.setAttribute('readonly', '');
  el.style.position = 'absolute';
  el.style.left = '-9999px';
  document.body.appendChild(el);

  el.select();                              // select its content
  document.execCommand('copy');             // 👉 tries to copy
  document.body.removeChild(el);            // tidy up
}

It works (even in quirky WebViews and IE 11), but it comes with warts:

  • Uses document.execCommand('copy'), now deprecated and removable at any moment.

  • Can scroll the page or open the mobile keyboard because focus jumps to the hidden element.

  • Fails inside Shadow DOM or sandboxed iframes.


Meet navigator.clipboard

All evergreen browsers now support a much cleaner, promise-based API:

async function copy(text) {
  await navigator.clipboard.writeText(text);
  console.log('Copied ✔');
}

Why it’s better

execCommand() hacknavigator.clipboard
Requires HTTPS✅ (secure context)
Returns a Promise❌ (sync)
Reads and writes❌ (write-only)readText() / read()
Handles images & blobs
Permission controlMinimalGranular, auditable

A Future-Proof Helper

The safest approach is a tiny feature-test wrapper:

export async function copyText(text) {
  if (navigator.clipboard?.writeText) {
    return navigator.clipboard.writeText(text);   // modern path
  }

  // fallback for legacy browsers
  const el = document.createElement('textarea');
  el.value = text;
  el.style.position = 'fixed';   // avoid scrolling jump
  el.style.opacity = '0';
  document.body.appendChild(el);
  el.focus();
  el.select();
  document.execCommand('copy');
  document.body.removeChild(el);
}

Best Practices

  1. Call in response to a user gesture (click, key press). Browsers block clipboard writes otherwise.

  2. Gracefully handle rejections. the user may deny permission or the OS clipboard could be unavailable.

  3. Don’t UA-sniff. Feature-test (navigator.clipboard?.writeText) and fallback when missing.


Takeaway

By 2025, the Clipboard API should be your default. Keep the legacy shim for those edge-case WebViews, but stop sprinkling hidden <textarea> elements around your app. Cleaner code, happier users, and one less deprecated API to worry about.

0
Subscribe to my newsletter

Read articles from Amir Yurista directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Amir Yurista
Amir Yurista