The Clipboard API is a modern, Promise-based browser API for reading from and writing to the user’s clipboard without any Flash dependencies, third-party libraries, or the deprecated document.execCommand(‘copy’) hack. It is the correct way to implement “Copy to clipboard” buttons in 2022 and beyond. The API has two main methods: navigator.clipboard.writeText(text) writes a string to the clipboard and returns a Promise, and navigator.clipboard.readText() reads from the clipboard and returns a Promise that resolves with the clipboard string. Reading requires explicit user permission (a browser permission prompt), but writing only requires the page to be the active, focused document — no permission prompt needed for copy. The Clipboard API requires HTTPS — it is not available on http:// pages. For WordPress specifically, “Copy to clipboard” is useful for code snippet blocks, referral links, shortcodes, and API keys displayed in the admin. The fallback for older browsers (IE, old Edge) is the document.execCommand(‘copy’) approach — you can detect support with navigator.clipboard check and branch accordingly. For the Intersection Observer and other modern browser APIs used in WordPress themes, see the Intersection Observer guide; for error handling of the async Clipboard API methods, see the try/catch guide.
Problem: You need a “Copy to clipboard” button for code blocks, referral links, or API keys in your WordPress theme or admin pages, without jQuery plugins or Flash.
Solution: Add the following JavaScript to your theme or plugin:
// Basic copy to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (err) {
// Fallback for non-HTTPS or older browsers
const ta = document.createElement('textarea');
ta.value = text;
ta.style.cssText = 'position:fixed;opacity:0;pointer-events:none';
document.body.appendChild(ta);
ta.select();
const ok = document.execCommand('copy');
document.body.removeChild(ta);
return ok;
}
}
// Attach to all "Copy" buttons
// HTML: <button class="copy-btn" data-copy="TEXT TO COPY">Copy</button>
document.querySelectorAll('.copy-btn').forEach(btn => {
btn.addEventListener('click', async () => {
const text = btn.dataset.copy || btn.closest('[data-copy]')?.dataset.copy;
if (!text) return;
const ok = await copyToClipboard(text);
if (ok) {
const original = btn.textContent;
btn.textContent = 'Copied!';
btn.disabled = true;
setTimeout(() => {
btn.textContent = original;
btn.disabled = false;
}, 2000);
}
});
});
// Copy code block content on click
// Adds a "Copy" button to every block (e.g. cedaro/code blocks)
document.querySelectorAll('pre code').forEach(codeEl => {
const pre = codeEl.parentElement;
pre.style.position = 'relative';
const btn = document.createElement('button');
btn.textContent = 'Copy';
btn.className = 'code-copy-btn';
btn.style.cssText = 'position:absolute;top:8px;right:8px;padding:4px 10px;font-size:12px;cursor:pointer;';
pre.appendChild(btn);
btn.addEventListener('click', async () => {
const ok = await copyToClipboard(codeEl.textContent);
if (ok) {
btn.textContent = 'Copied!';
setTimeout(() => btn.textContent = 'Copy', 2000);
}
});
});
// Read from clipboard (requires user permission prompt)
async function pasteFromClipboard() {
try {
return await navigator.clipboard.readText();
} catch (err) {
console.error('Clipboard read failed:', err);
return '';
}
}
NOTE: navigator.clipboard is only available in secure contexts (HTTPS) and when the document is focused. If your WordPress admin or front end runs over HTTP (during local development, for example), the Clipboard API will be undefined and the fallback execCommand path will run instead. Always test the fallback path locally. The execCommand API is officially deprecated but still works in all browsers as of 2022 — it is a safe fallback. For production WordPress sites, HTTPS is mandatory anyway for Google ranking and browser security features, so the Clipboard API should always be available.