🚀AdvancedAdvanced Forms

Clipboard API

Copy text and rich content to and from the clipboard using the modern async Clipboard API and handle paste events for custom input behavior.

Overview

The Clipboard API provides programmatic read/write access to the system clipboard. The modern async API (`navigator.clipboard`) replaces the legacy `document.execCommand('copy')` with Promise-based methods that work in all modern browsers and respect user permissions. `navigator.clipboard.writeText(text)` copies a string to the clipboard. `navigator.clipboard.readText()` reads text back. For rich content (images, HTML, multiple types), use `navigator.clipboard.write([new ClipboardItem(...)])`. Reading clipboard content requires explicit user permission in most browsers. The `paste`, `copy`, and `cut` events fire on editable elements and the document, giving you access to the `ClipboardEvent.clipboardData` object to read or modify what is being copied/pasted.

Key Points

  • •`navigator.clipboard.writeText(str)` write text to clipboard (requires secure context: HTTPS or localhost)
  • •`navigator.clipboard.readText()` read text from clipboard (requires "clipboard-read" permission)
  • •`ClipboardItem` enables copying rich content (images, HTML) alongside plain text
  • •The `copy`, `cut`, `paste` events fire on editable elements; access data via `event.clipboardData`
  • •`event.clipboardData.setData(type, data)` in a copy event lets you customize what gets copied
  • •`event.clipboardData.getData(type)` in a paste event reads the clipboard before insertion
  • •Clipboard read access requires user permission browsers may show a prompt

Examples

Copy to clipboard with user feedback

<button id="copy-btn" data-copy="npm install react">
  Copy Install Command
</button>

<script>
document.getElementById('copy-btn').addEventListener('click', async (e) => {
  const text = e.currentTarget.dataset.copy;

  try {
    await navigator.clipboard.writeText(text);

    // Provide visual feedback
    const btn = e.currentTarget;
    const original = btn.textContent;
    btn.textContent = '✓ Copied!';
    btn.disabled = true;
    setTimeout(() => {
      btn.textContent = original;
      btn.disabled = false;
    }, 2000);
  } catch (err) {
    console.error('Copy failed:', err);
    // Fallback for older browsers
    fallbackCopy(text);
  }
});

function fallbackCopy(text) {
  const ta = document.createElement('textarea');
  ta.value = text;
  ta.style.position = 'fixed';
  ta.style.opacity = '0';
  document.body.appendChild(ta);
  ta.select();
  document.execCommand('copy');
  document.body.removeChild(ta);
}
</script>

Always provide visual feedback after copying users need confirmation that the action worked.

Intercepting the paste event to sanitize input

<div
  id="rich-editor"
  contenteditable="true"
  role="textbox"
  aria-multiline="true"
>Type or paste here...</div>

<script>
document.getElementById('rich-editor').addEventListener('paste', (event) => {
  event.preventDefault();

  // Get pasted text, stripping all HTML/formatting
  const text = event.clipboardData.getData('text/plain');

  // Insert as plain text at cursor position
  document.execCommand('insertText', false, text);
  // OR in modern browsers:
  // document.getSelection().getRangeAt(0).insertNode(document.createTextNode(text));
});
</script>

Preventing the default paste and inserting only plain text is a common pattern for rich text editors that should not accept formatted paste.

Copying rich content (image + text) with ClipboardItem

<img id="chart" src="chart.png" alt="Sales chart">
<button id="copy-image">Copy Chart</button>

<script>
document.getElementById('copy-image').addEventListener('click', async () => {
  const img = document.getElementById('chart');

  try {
    // Fetch the image as a Blob
    const response = await fetch(img.src);
    const blob = await response.blob();

    await navigator.clipboard.write([
      new ClipboardItem({
        [blob.type]: blob,          // image/png
        'text/plain': new Blob(
          ['Sales Chart Q4 2024'],
          { type: 'text/plain' }
        ),
      })
    ]);

    alert('Chart copied to clipboard!');
  } catch (err) {
    console.error('Rich copy failed:', err);
  }
});
</script>

ClipboardItem lets you provide multiple MIME types the recipient's app picks the richest format it supports.

Common Mistakes

  • Using the Clipboard API outside a user gesture browsers require a user action (click, keydown) to access the clipboard
  • Not handling the permission error when `readText()` is called users can deny clipboard-read permission
  • Forgetting the secure context requirement the Clipboard API only works on HTTPS or localhost

Note

The legacy `document.execCommand("copy")` is deprecated but still useful as a fallback. Always try the modern Clipboard API first, then fall back to execCommand in a catch block.

Exercises

Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What security requirement must be met to use navigator.clipboard?