JavaScript Clipboard API: A Complete Tutorial
Learn how to copy and paste text programmatically using the modern async Clipboard API, handle permissions, and fall back for older browsers.
The Clipboard API gives JavaScript direct access to the system clipboard through a modern, async interface. You can copy text to the clipboard and read text from it without relying on hidden textarea hacks or the deprecated document.execCommand approach.
Here is the simplest copy operation using the new API:
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
console.log("Copied to clipboard");
} catch {
console.log("Failed to copy");
}
}
copyText("Hello from JavaScript");The function calls writeText, which returns a promise. If the browser supports the API and the page is served over HTTPS, the text lands on the clipboard and the promise resolves. If anything goes wrong, the catch block handles it gracefully.
How the Clipboard API works
The API lives on navigator.clipboard and provides four main methods. The writeText and readText methods are the simplest, handling plain text only. For richer data, write and read accept ClipboardItem objects.
| Method | What it does |
|---|---|
| writeText(text) | Copies a string to the clipboard |
| readText() | Reads text from the clipboard |
| write([ClipboardItem]) | Copies rich data like images or HTML |
| read() | Reads rich data from the clipboard |
The API is only available in secure contexts. On pages served over HTTP, navigator.clipboard is undefined. You need HTTPS or localhost during development.
Copying text on a button click
In real applications, clipboard access must be triggered by a user gesture. Browsers block programmatic clipboard writes that happen without a click, keypress, or similar interaction.
Here is a practical button that copies text from an input field:
document.querySelector("#copyButton").addEventListener("click", async () => {
const text = document.querySelector("#sourceInput").value;
try {
await navigator.clipboard.writeText(text);
console.log("Text copied");
} catch {
console.log("Copy failed");
}
});The async function runs inside a click handler, satisfying the user gesture requirement. If the copy succeeds, the text is on the clipboard and ready to paste anywhere.
Reading text from the clipboard
Reading requires the clipboard-read permission. Browsers typically grant it automatically when the user performs a paste gesture, but programmatic reads may trigger a permission prompt.
document.querySelector("#pasteButton").addEventListener("click", async () => {
try {
const text = await navigator.clipboard.readText();
document.querySelector("#output").textContent = text;
} catch {
console.log("Paste failed or permission denied");
}
});The readText method returns a promise that resolves with the clipboard's current text content. If the user denied permission or the clipboard is empty, the promise rejects.
Checking Clipboard API availability
Since the API requires a secure context, always check for support before calling any method:
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText("Supported");
} else {
console.log("Clipboard API not available, use fallback");
}This check guards against both insecure contexts and older browsers where navigator.clipboard is undefined. When the API is missing, fall back to the older document.execCommand approach described below.
Fallback for older browsers
Before the Clipboard API, the only way to copy text was document.execCommand. This approach needs a hidden textarea, because execCommand only copies whatever text is currently selected on the page:
function createHiddenTextarea(text) {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.opacity = "0";
document.body.appendChild(textarea);
textarea.select();
return textarea;
}This helper builds an invisible textarea, fills it with the text to copy, and selects its content so execCommand has something to act on. With the textarea ready, the actual copy and cleanup happen in a second function:
function fallbackCopy(text) {
const textarea = createHiddenTextarea(text);
try {
document.execCommand("copy");
console.log("Copied via fallback");
} catch {
console.log("Fallback copy failed");
} finally {
document.body.removeChild(textarea);
}
}This pattern is widely used but has drawbacks. It manipulates the DOM, briefly creates a visible selection on some screen readers, and only works for text. The async Clipboard API is the preferred approach whenever available.
Common mistakes
- Calling clipboard methods outside a user gesture. Browsers reject clipboard access without a click, keypress, or similar interaction.
- Forgetting the secure context requirement. navigator.clipboard is undefined on HTTP pages.
- Not handling promise rejection. Clipboard operations can fail due to permissions, browser settings, or empty clipboards.
- Assuming readText always works without permission. Browsers may prompt or silently deny read access.
- Using execCommand without first checking for the async API. Always prefer the modern API and fall back only when necessary.
Related articles
- How to Add Event Listeners in JS: Complete Guide -- the foundation for clipboard interactions tied to user gestures
- Handling Click Events in JavaScript: Full Guide -- clipboard operations are typically triggered by clicks
- JavaScript Notifications API: Complete Tutorial -- another permission-based browser API
Quick reference
| Operation | Modern API | Fallback |
|---|---|---|
| Copy text | navigator.clipboard.writeText(text) | document.execCommand("copy") |
| Read text | navigator.clipboard.readText() | Not available |
| Check support | if (navigator.clipboard) | Use execCommand |
| Secure context | Required (HTTPS/localhost) | Works on HTTP |
| User gesture | Required for write | Required |
Rune AI
Key Insights
- navigator.clipboard.writeText copies text to the clipboard asynchronously.
- navigator.clipboard.readText reads text from the clipboard, but requires permission.
- The Clipboard API only works in secure contexts (HTTPS or localhost).
- Always check navigator.clipboard availability and fall back to execCommand for older browsers.
- Clipboard access must be triggered by a user gesture like a click or keypress.
Frequently Asked Questions
Does the Clipboard API work in all browsers?
Do I need HTTPS to use the Clipboard API?
Can I copy images or rich text with the Clipboard API?
Why does readText show a permission prompt?
Conclusion
The async Clipboard API replaces the old document.execCommand approach with a clean promise-based interface. Use writeText to copy and readText to paste. Always check for API availability and handle the permission model gracefully. For production apps, keep the execCommand fallback for older browsers.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.