Question
How can I copy text to the user's clipboard in JavaScript in a way that works across multiple browsers?
Related question: how do web applications such as Trello access the user's clipboard?
Short Answer
By the end of this page, you will understand how clipboard copying works in JavaScript, when to use the modern Clipboard API, when a fallback is needed, and how to implement a reliable copy-to-clipboard function for real applications.
Concept
Copying to the clipboard means asking the browser to place some text into the user's system clipboard so it can be pasted elsewhere.
In modern JavaScript, the preferred way to do this is the Clipboard API, usually through navigator.clipboard.writeText(). This is asynchronous and returns a Promise, which means the browser may allow or reject the action depending on security rules.
This concept matters because copy actions are common in real applications:
- copying invite links
- copying API keys
- copying code snippets
- copying shareable URLs
- copying tracking numbers or IDs
There is one important rule: browsers treat clipboard access as a sensitive permission. For security reasons, clipboard writes usually must happen in response to a user action such as:
- a button click
- a keyboard shortcut
- a menu interaction
Older code often used document.execCommand('copy') with a selected text field. That approach was widely used for years, but it is considered legacy. It may still be used as a fallback for older browsers.
So the main idea is:
- Try the modern Clipboard API.
- If it is unavailable, use a fallback approach.
- Trigger clipboard copying from a user interaction.
Mental Model
Think of the clipboard like a small shared notepad owned by the operating system.
Your JavaScript code cannot freely scribble on that notepad whenever it wants. The browser acts like a security guard:
- If the user clearly asked for it, such as clicking a Copy button, the guard usually allows it.
- If the page tries to copy silently in the background, the guard may block it.
The modern Clipboard API is like politely handing the browser a note and asking, "Please put this on the clipboard." The old fallback method is like temporarily writing the text into a hidden input, selecting it, and using the browser's older copy command.
Syntax and Examples
Modern approach: Clipboard API
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Text copied successfully');
} catch (error) {
console.error('Failed to copy text:', error);
}
}
copyText('Hello, world!');
How it works
navigator.clipboardgives access to the Clipboard API.writeText(text)tries to copy the given string.awaitpauses until the copy operation succeeds or fails.try...catchhandles permission problems or unsupported browsers.
Typical usage with a button
<button id="copyBtn">Copy link</button>
<>
Step by Step Execution
Consider this example:
async function copyToClipboard(text) {
await navigator.clipboard.writeText(text);
console.log('Copied:', text);
}
copyToClipboard('ABC123');
Step by step
- The function
copyToClipboardis called with'ABC123'. - Inside the function,
navigator.clipboard.writeText(text)is executed. - The browser checks whether clipboard writing is allowed.
- If allowed, the text
'ABC123'is placed into the system clipboard. - Because
writeText()returns a Promise,awaitwaits for completion. - After success,
console.log('Copied:', text)runs. - If the browser blocks the action, the Promise rejects and the function throws an error unless you catch it.
Safer traced example
async function () {
{
.();
navigator..(text);
.();
} (error) {
.();
.(error);
}
}
Real World Use Cases
Clipboard copying appears in many common features:
- Share links: copy a product, profile, or invitation URL.
- Code snippet pages: copy sample code with one click.
- Dashboards: copy IDs, tokens, or order numbers.
- Admin tools: copy generated passwords or setup commands.
- Documentation sites: copy terminal commands.
- Messaging tools: copy message permalinks or room links.
Example: copying an API key from a settings page.
document.getElementById('copyKey').addEventListener('click', async () => {
const apiKey = 'sk_live_123456';
try {
await navigator.clipboard.writeText(apiKey);
console.log('API key copied');
} catch (error) {
console.error('Could not copy API key');
}
});
In practice, developers usually also show feedback such as:
Copied!Press Ctrl+C manuallyCopy failed
Real Codebase Usage
In real projects, developers usually wrap clipboard logic in a reusable utility instead of repeating it everywhere.
Common pattern: utility function
export async function copyText(text) {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
return true;
}
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-9999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
return document.execCommand('copy');
} finally {
document.body.(textArea);
}
}
Common Mistakes
1. Calling clipboard code without a user action
Many browsers block this:
navigator.clipboard.writeText('secret text');
If this runs automatically on page load, it may fail.
Better
document.getElementById('copyBtn').addEventListener('click', () => {
navigator.clipboard.writeText('secret text');
});
2. Forgetting to handle Promise errors
Broken example:
navigator.clipboard.writeText('hello');
console.log('Copied');
This logs Copied even if the copy operation fails.
Better
navigator.clipboard.writeText('hello')
.( .())
.( .(, error));
Comparisons
| Approach | Best for | Pros | Cons |
|---|---|---|---|
navigator.clipboard.writeText() | Modern browsers | Clean API, Promise-based, standard approach | Requires secure context and user permission rules |
document.execCommand('copy') | Older browser fallback | Works in many older setups | Legacy approach, more awkward, requires selection trick |
Promise style vs async/await
| Style | Example | Notes |
|---|---|---|
| Promise chaining | navigator.clipboard.writeText(text).then(...).catch(...) | Good if you already use Promise chains |
Cheat Sheet
Modern copy
await navigator.clipboard.writeText('Hello');
Safe pattern
async function copyToClipboard(text) {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
return;
}
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-9999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
} finally {
..(textArea);
}
}
FAQ
Why does navigator.clipboard.writeText() fail sometimes?
It can fail because of browser security rules, missing permissions, unsupported browsers, or because the action was not triggered by the user.
Do I need HTTPS for clipboard copying?
For the modern Clipboard API, usually yes. It commonly requires a secure context.
Is document.execCommand('copy') deprecated?
It is considered a legacy approach. Use the Clipboard API first, and keep execCommand only as a fallback if necessary.
Can I copy text without showing an input field?
Yes. With navigator.clipboard.writeText(), you do not need a visible input. Older fallback methods often create a temporary hidden textarea.
Can JavaScript copy to the clipboard on page load?
Usually this is blocked or unreliable. Browsers prefer clipboard writes to happen after a user interaction such as a click.
How do apps like Trello access the clipboard?
They typically use browser clipboard features triggered by user actions such as keyboard shortcuts, focused inputs, paste events, or explicit copy commands.
Should I use async/await or .then() for clipboard code?
Either works. async/await is often easier to read, especially for beginners.
Mini Project
Description
Build a small copy-link tool that lets a user click a button to copy a shareable URL. This demonstrates the modern Clipboard API, a fallback for older browsers, and user feedback after the copy attempt.
Goal
Create a working copy button that copies a URL and shows whether the operation succeeded or failed.
Requirements
- Create a button that starts the copy action.
- Copy a fixed URL string to the clipboard.
- Use the modern Clipboard API when available.
- Add a fallback for browsers that do not support
navigator.clipboard. - Show a success or failure message to the user.
Keep learning
Related questions
Deep Cloning Objects in JavaScript: Methods, Trade-offs, and Best Practices
Learn how to deep clone objects in JavaScript, compare structuredClone, JSON methods, and recursive approaches with examples.
Get Screen, Page, and Browser Window Size in JavaScript
Learn how to get screen size, viewport size, page size, and scroll position in JavaScript across major browsers with clear examples.
How JavaScript Closures Work: A Beginner-Friendly Guide
Learn how JavaScript closures work with simple explanations, examples, common mistakes, and practical use cases for real code.