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.clipboardonly 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.
๐ You Might Also Like
- โ Best Google AdSense Alternative 2026 - Monetag Review for Publishers miscellaneous
- โ How to Start Freelancing as a Web Developer in 2026 (Complete Beginner's Guide) miscellaneous
- โ HTTP QUERY Method (RFC 10008) โ The New HTTP Method Every Developer Should Know miscellaneous
- โ JavaScript Array Methods Cheat Sheet โ Complete Guide with Example javascript
- โ MyLync โ Best Free Linktree Alternative for Developers, Creators & Businesses miscellaneous