demo · v133

Async screenshot copy — long render, user-gesture-bound copy

A user clicks "copy chart as image". Drawing the chart takes 700ms. Before 133, you had to await the Blob and then call clipboard.write — but by then the user gesture had expired and the call failed. Pass a promise for the Blob to new ClipboardItem: the user gesture is captured up front, the image is generated in the background.

the code

// Before 133:
button.addEventListener("click", async () => {
  const blob = await renderBigChart();   // 700ms — user gesture lost
  await navigator.clipboard.write([
    new ClipboardItem({ "image/png": blob }),
  ]);
});

// After 133:
button.addEventListener("click", () => {
  navigator.clipboard.write([
    new ClipboardItem({
      "image/png": renderBigChart(),   // promise! user gesture preserved
    }),
  ]);
});

Same change applies to text/plain: new ClipboardItem({ "text/plain": fetchAsyncText() }). The browser awaits the promise on the gesture's behalf, so the clipboard write is treated as user-initiated even when the data resolves seconds later. The 133 update also accepts a plain DOMString directly — new ClipboardItem({ "text/plain": "hi" }) — instead of forcing a Blob/Promise dance for simple text.

see also