← thecodex.expert · The Codex Family of Knowledge
The Codex / JavaScript / Clipboard API

Clipboard API

Reading from and writing to the system clipboard — copy, cut, paste, rich content, and the legacy document.execCommand fallback.

What it is, in plain English: The Clipboard API provides modern, permission-based access to the system clipboard. navigator.clipboard.writeText(text) copies text programmatically. navigator.clipboard.readText() reads the clipboard (requires permission). The ClipboardItem interface supports rich content — HTML, images, and custom MIME types. For simple copy-to-clipboard buttons, writeText() is all you need.
Where this bites you

navigator.clipboard only exists in a secure context: HTTPS, or localhost during development. Open the same page over plain HTTP, such as a staging server or your laptop's LAN address on a phone, and navigator.clipboard is undefined. The copy button throws a TypeError, nothing is copied, and the user gets no feedback at all.

const copyBtn = document.querySelector("#copy-btn");
const codeEl  = document.querySelector("pre");

copyBtn.addEventListener("click", async () => {
  await navigator.clipboard.writeText(codeEl.textContent);
  copyBtn.textContent = "✓ Copied!";
});
// page opened over plain HTTP, e.g. http://staging.test (not localhost):
console.log(window.isSecureContext, typeof navigator.clipboard);
// false "undefined"
// click -> TypeError: Cannot read properties of undefined (reading 'writeText')

Copy and paste from JavaScript

Copy text to clipboard

// The simplest pattern — copy any text:
async function copyText(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log("Copied!");
  } catch (error) {
    console.error("Copy failed:", error);
  }
}

// A copy button that gives feedback:
const copyBtn = document.querySelector("#copy-btn");
const codeEl  = document.querySelector("pre");

copyBtn.addEventListener("click", async () => {
  await navigator.clipboard.writeText(codeEl.textContent);
  copyBtn.textContent = "✓ Copied!";
  setTimeout(() => { copyBtn.textContent = "Copy"; }, 2000);
});

The copyText() helper above at least catches the error, but the button version doesn't. Check window.isSecureContext first, fall back to the legacy execCommand("copy") technique (covered in the Intermediate tab) on plain HTTP, and always tell the user what happened:

const copyBtn = document.querySelector("#copy-btn");
const codeEl  = document.querySelector("pre");

async function copy(text) {
  if (window.isSecureContext && navigator.clipboard) {
    await navigator.clipboard.writeText(text);   // HTTPS or localhost
    return true;
  }
  return legacyCopy(text);                       // plain HTTP: fall back
}

function legacyCopy(text) {
  const el = document.createElement("textarea");
  el.value = text;
  el.style.position = "absolute";
  el.style.left = "-9999px";
  document.body.appendChild(el);
  el.select();
  const ok = document.execCommand("copy");
  document.body.removeChild(el);
  return ok;
}

copyBtn.addEventListener("click", async () => {
  try {
    const ok = await copy(codeEl.textContent);
    copyBtn.textContent = ok ? "✓ Copied!" : "Press Ctrl+C to copy";
  } catch {
    copyBtn.textContent = "Press Ctrl+C to copy";   // never leave the user guessing
  }
  console.log(copyBtn.textContent);
});
// "✓ Copied!"  (on http://staging.test and on localhost)

Reading the clipboard

// Reading requires user permission (browser asks):
async function pasteText() {
  try {
    const text = await navigator.clipboard.readText();
    input.value = text;  // paste into an input
  } catch (error) {
    // User denied or clipboard access not available
    console.error(error.message);
  }
}

// Listen for paste events (no permission needed — user initiates):
document.addEventListener("paste", (event) => {
  const text = event.clipboardData.getData("text/plain");
  console.log("User pasted:", text);
  event.preventDefault();  // prevent default paste behaviour
});
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.