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.

5 min read

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:

javascriptjavascript
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.

MethodWhat 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:

javascriptjavascript
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.

javascriptjavascript
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:

javascriptjavascript
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:

javascriptjavascript
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:

javascriptjavascript
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.

Quick reference

OperationModern APIFallback
Copy textnavigator.clipboard.writeText(text)document.execCommand("copy")
Read textnavigator.clipboard.readText()Not available
Check supportif (navigator.clipboard)Use execCommand
Secure contextRequired (HTTPS/localhost)Works on HTTP
User gestureRequired for writeRequired
Rune AI

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.
RunePowered by Rune AI

Frequently Asked Questions

Does the Clipboard API work in all browsers?

The async Clipboard API is supported in all modern browsers including Chrome, Firefox, Safari, and Edge. However, the readText method requires explicit user permission and may not work in all contexts without a user gesture.

Do I need HTTPS to use the Clipboard API?

Yes. The Clipboard API requires a secure context (HTTPS or localhost). On HTTP pages, navigator.clipboard is undefined and you must fall back to document.execCommand.

Can I copy images or rich text with the Clipboard API?

Yes. Use navigator.clipboard.write() to copy arbitrary data including images and HTML. The writeText method is a convenience for plain text only.

Why does readText show a permission prompt?

Reading the clipboard could expose sensitive data like passwords. Browsers require the page to have the clipboard-read permission granted by the user, typically through a permissions prompt or a user gesture.

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.