How to copy text on a button click using JavaScript

๐Ÿ‘๏ธ 35 Views
|
๐Ÿ“… Jul 19, 2026
|
โฑ๏ธ 12 min read
How to copy text on a button click using JavaScript

The "Copy to Clipboard" button is one of those small features that has a huge impact on user experience. Code snippet sites, password managers, referral link pages, coupon code boxes โ€” nearly every modern web application uses it somewhere. And the good news is that implementing it in JavaScript is much simpler than most developers expect.

In this guide we will cover three different ways to copy text to the clipboard using JavaScript โ€” from the old approach using execCommand to the modern Clipboard API that is now the recommended standard โ€” along with practical examples for every common use case you will encounter.

Method 1 โ€” The Old Way Using execCommand (Still Works)

The original approach uses document.execCommand("copy") which has been available in browsers for a long time. It works by selecting text in an input or textarea element and then triggering the copy command programmatically โ€” exactly like the user pressing Ctrl + C.

Copying Text From a Textarea

<!-- HTML -->
<textarea id="textArea" cols="45" rows="6">
  Hey! Just click the button below to copy this entire text.
</textarea>
<button onclick="copyText()">Copy to Clipboard</button>
<p id="message"></p>
// JavaScript
function copyText() {
  let textArea = document.querySelector("#textArea");

  // Step 1 โ€” select the text inside the textarea
  textArea.select();

  // Step 2 โ€” for mobile devices (iOS fix)
  textArea.setSelectionRange(0, 99999);

  // Step 3 โ€” execute the copy command
  document.execCommand("copy");

  // Step 4 โ€” give visual feedback to the user
  document.getElementById("message").textContent = "โœ… Text copied to clipboard!";

  // Step 5 โ€” clear the message after 2 seconds
  setTimeout(() => {
    document.getElementById("message").textContent = "";
  }, 2000);
}

The setSelectionRange(0, 99999) call on line 5 is important for mobile browsers โ€” especially iOS Safari โ€” which require an explicit selection range before the copy command works.

Note: document.execCommand() is marked as deprecated in the official Web API specification. It still works in all major browsers today, but the modern Clipboard API (covered in Method 2 below) is the recommended approach for new projects.

Method 2 โ€” The Modern Way Using the Clipboard API (Recommended)

The Clipboard API was introduced to replace execCommand and provides a cleaner, promise-based interface for reading and writing to the clipboard. It works with any text โ€” not just text inside form elements โ€” and handles the async nature of clipboard operations properly.

Copy Any Text String to Clipboard

// Copy any string directly โ€” no textarea needed
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log("Text copied successfully!");
  } catch (err) {
    console.error("Failed to copy text: ", err);
  }
}

// Usage
copyToClipboard("Hello, this text is now in your clipboard!");

Copy Button With Visual Feedback

<!-- HTML -->
<div>
  <p id="textToCopy">This is the text that will be copied to your clipboard.</p>
  <button id="copyBtn" onclick="copyText()">๐Ÿ“‹ Copy Text</button>
</div>
// JavaScript โ€” Modern Clipboard API
async function copyText() {
  const text   = document.getElementById("textToCopy").innerText;
  const button = document.getElementById("copyBtn");

  try {
    await navigator.clipboard.writeText(text);

    // Change button text to confirm copy
    button.textContent = "โœ… Copied!";
    button.style.backgroundColor = "#16a34a"; // green

    // Reset button after 2 seconds
    setTimeout(() => {
      button.textContent = "๐Ÿ“‹ Copy Text";
      button.style.backgroundColor = "";
    }, 2000);

  } catch (err) {
    button.textContent = "โŒ Failed to copy";
    console.error("Clipboard error:", err);
  }
}

Method 3 โ€” Copy Input Field Value on Button Click

A very common use case is copying the value from an input field โ€” like a referral link, promo code, or generated password:

<!-- HTML -->
<div style="display:flex; gap:8px;">
  <input
    type="text"
    id="referralLink"
    value="https://tipsandtricks.dev?ref=ABC123"
    readonly
    style="width:300px; padding:8px;"
  />
  <button onclick="copyInput()">Copy Link</button>
</div>
<span id="copyStatus"></span>
// JavaScript
async function copyInput() {
  const input  = document.getElementById("referralLink");
  const status = document.getElementById("copyStatus");

  try {
    // Modern approach โ€” copy the input value directly
    await navigator.clipboard.writeText(input.value);
    status.textContent = "โœ… Link copied!";
    status.style.color = "#16a34a";
  } catch (err) {
    // Fallback for older browsers
    input.select();
    document.execCommand("copy");
    status.textContent = "โœ… Link copied!";
  }

  setTimeout(() => { status.textContent = ""; }, 2000);
}

Reusable Copy Button Component

If you need copy buttons in multiple places across your site, write a single reusable function instead of repeating the logic everywhere:

// Reusable copy function โ€” works anywhere on your page
async function copyToClipboard(text, feedbackElement) {
  try {
    await navigator.clipboard.writeText(text);

    if (feedbackElement) {
      const original = feedbackElement.textContent;
      feedbackElement.textContent = "โœ… Copied!";
      setTimeout(() => {
        feedbackElement.textContent = original;
      }, 2000);
    }

    return true;
  } catch (err) {
    console.error("Copy failed:", err);
    return false;
  }
}

// Using it anywhere
document.getElementById("btn1").addEventListener("click", function() {
  copyToClipboard("First text to copy", this);
});

document.getElementById("btn2").addEventListener("click", function() {
  copyToClipboard("Second text to copy", this);
});

document.getElementById("btn3").addEventListener("click", function() {
  const code = document.getElementById("codeBlock").innerText;
  copyToClipboard(code, this);
});

Copy Code Snippet on Button Click

One of the most popular use cases on developer blogs and documentation sites is adding a "Copy" button to code blocks. Here is a clean implementation:

<!-- HTML -->
<div class="code-block" style="position:relative; background:#1f2937; padding:1rem; border-radius:8px;">
  <button
    onclick="copyCode(this)"
    style="position:absolute; top:8px; right:8px; padding:4px 10px; font-size:12px; cursor:pointer;"
  >
    Copy
  </button>
  <pre><code id="snippet1">console.log("Hello, World!");</code></pre>
</div>
// JavaScript โ€” copies code from the nearest code block
async function copyCode(button) {
  // Find the code element inside the same container
  const code = button.nextElementSibling.querySelector("code").innerText;

  try {
    await navigator.clipboard.writeText(code);
    button.textContent = "Copied โœ…";
    button.style.color = "#4ade80";
    setTimeout(() => {
      button.textContent = "Copy";
      button.style.color = "";
    }, 2000);
  } catch (err) {
    button.textContent = "Failed โŒ";
  }
}

Handling Browser Permissions

The Clipboard API requires the user's permission on some browsers, especially for reading from the clipboard. For writing (which is what copy does), most browsers allow it automatically when triggered by a user action like a button click. However there are a few things to be aware of:

  • HTTPS required โ€” navigator.clipboard only works on pages served over HTTPS or on localhost. It will be undefined on plain HTTP pages.
  • Must be triggered by user action โ€” you cannot call the Clipboard API from a timer or on page load. It must be called directly from a user event like a click.
  • Browser support โ€” the Clipboard API is supported in all modern browsers (Chrome 66+, Firefox 63+, Safari 13.1+, Edge 79+). For older browsers, always provide the execCommand fallback.

Full Example With Fallback for All Browsers

Here is a production-ready copy function that uses the modern Clipboard API when available and falls back to execCommand for older browsers:

async function copyTextUniversal(text) {
  // Modern browsers โ€” Clipboard API
  if (navigator.clipboard && window.isSecureContext) {
    try {
      await navigator.clipboard.writeText(text);
      return true;
    } catch (err) {
      console.warn("Clipboard API failed, trying fallback...");
    }
  }

  // Fallback โ€” create a temporary textarea
  const textArea       = document.createElement("textarea");
  textArea.value       = text;
  textArea.style.position = "fixed";   // prevent page scroll
  textArea.style.top      = "-9999px";
  textArea.style.left     = "-9999px";
  textArea.style.opacity  = "0";

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();
  textArea.setSelectionRange(0, 99999); // for mobile

  try {
    const success = document.execCommand("copy");
    document.body.removeChild(textArea);
    return success;
  } catch (err) {
    document.body.removeChild(textArea);
    console.error("Both copy methods failed:", err);
    return false;
  }
}

// Usage
document.getElementById("copyBtn").addEventListener("click", async function() {
  const success = await copyTextUniversal("Text to copy here");
  this.textContent = success ? "โœ… Copied!" : "โŒ Failed";
  setTimeout(() => { this.textContent = "Copy"; }, 2000);
});

Common Mistakes to Avoid

1. Not giving visual feedback

Always confirm to the user that something happened. Without feedback, users will click the button repeatedly not knowing if it worked. Change the button text, show a tick, or briefly change the color โ€” anything to confirm the action succeeded.

2. Calling Clipboard API outside a user event

// โŒ Wrong โ€” calling clipboard on page load will be blocked by browser
window.onload = async function() {
  await navigator.clipboard.writeText("auto copy"); // Blocked!
};

// โœ… Correct โ€” always triggered by user interaction
button.addEventListener("click", async function() {
  await navigator.clipboard.writeText("user clicked"); // Works
});

3. Not handling errors

// โŒ Wrong โ€” no error handling, silent failure
async function copy() {
  await navigator.clipboard.writeText(text);
}

// โœ… Correct โ€” always use try/catch with async clipboard calls
async function copy() {
  try {
    await navigator.clipboard.writeText(text);
    showSuccess();
  } catch (err) {
    showError();
    console.error(err);
  }
}

4. Using execCommand on non-HTTP pages in new projects

If you are building a new project on HTTPS, use the Clipboard API. Only reach for execCommand as a fallback for older browser support. Do not make execCommand your primary approach in any code written after 2020.

Quick Comparison โ€” execCommand vs Clipboard API

execCommand Clipboard API
Status โš ๏ธ Deprecated โœ… Recommended
Works on HTTP โœ… Yes โŒ HTTPS only
Async / Promise โŒ Synchronous โœ… Promise-based
Copy any text โŒ Needs selected element โœ… Any string
Error handling โš ๏ธ Returns boolean โœ… try/catch
Browser support โœ… All including old โœ… All modern browsers

Final Thought

The "Copy to Clipboard" feature is one of the highest-impact, lowest-effort improvements you can add to any web project. Users expect it on anything that shows a code snippet, a link, a coupon code, or a wallet address. Without it, users have to manually select and copy text โ€” a small frustration that adds up quickly.

For any new project on HTTPS, use the Clipboard API with a try/catch and a fallback to execCommand. That combination gives you clean modern code with full backward compatibility. Add meaningful visual feedback on the button and you have a polished, production-ready copy feature in under 20 lines of code.

Building something with a copy feature and running into an issue in a specific browser? Drop us a message on our contact page and we will help you debug it.

Subscribe to Our Newsletter

Join Our Developer Community!

Unsubscribe Anytime | No Spam