v145 · Web APIs · Clipboard

Clipboardchange event

Chrome 145 ships the clipboardchange event — a window event that fires when the system clipboard contents change. The event requires sticky activation (a recent user gesture on the page) and the clipboard-read permission to deliver clipboard data in the handler. The event signals a change occurred; reading the value is a separate guarded step.

concepts

  1. Clipboard Monitor

    Live monitor that listens for clipboardchange events. Copy text anywhere and watch the event fire. Includes a permission request flow to read the new clipboard value inside the event handler.

  2. Activation & Permissions

    Explains the two gating requirements Chrome 145 enforces: sticky activation (a recent user interaction with the page) and clipboard-read permission. Shows a matrix of what is available at each permission state.

  3. Clipboard Differ

    Subscribe to clipboardchange, snapshot each change, and visually diff the new payload against the previous — character-level insertions in green, deletions in red. Useful for clipboard managers and paste-aware editors.

  4. Paste Preview

    A text editor that shows a "Paste ready" preview banner when clipboardchange fires. After sticky activation, copy text anywhere — the banner appears immediately with a one-click insert action, demonstrating the real-world paste-preview UX pattern.

why it shipped

Rich text editors, code editors, and clipboard managers need to know when clipboard contents change to update paste-preview UI or enable a "Paste" action. Previously the only option was polling navigator.clipboard.readText() on a timer — noisy, battery-draining, and requiring a persistent permission. The clipboardchange event lets apps react immediately and request clipboard-read only when needed, inside the trusted event handler context.

the API

// Listen for clipboard changes on window
window.addEventListener('clipboardchange', async () => {
  // The event fires — but to read the value, check permission first
  const { state } = await navigator.permissions.query({ name: 'clipboard-read' });

  if (state === 'granted') {
    const text = await navigator.clipboard.readText();
    console.log('Clipboard changed:', text);
  } else if (state === 'prompt') {
    // Inside a trusted event handler — browser can show permission UI
    try {
      const text = await navigator.clipboard.readText(); // prompts user
      console.log('Clipboard changed:', text);
    } catch {
      showManualPasteButton();
    }
  } else {
    // 'denied' — signal change but can't read value
    showPasteChangedBadge();
  }
});

// Requires: sticky activation (user gesture) + clipboard-read permission
// The event itself fires without permission; reading the value needs permission

references