I'm using javascript Clipboard API to copy an image to the clipboard. It works in Chrome and Edge but not in Safari in spite of official documentation of Safari says that it's supported. Check the documentation: https://webkit.org/blog/10855/ In this example (not my real code), write() throws an error: document.getElementById("copy").addEventListener("click", async function() { const response = await fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'); const blob = await response.blob(); navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]) .then(function () { console.log('copied'); }) .catch(function (error) { console.log(error); }); }); The given error is: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
(In reply to Felipe Ruiz from comment #0) > I'm using javascript Clipboard API to copy an image to the clipboard. It > works in Chrome and Edge but not in Safari in spite of official > documentation of Safari says that it's supported. The issue is not so much async Clipboard API and the difference in the way user activation is tracked between Blink and WebKit. > In this example (not my real code), write() throws an error: > > document.getElementById("copy").addEventListener("click", async function() { > const response = await > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/ > PNG_transparency_demonstration_1.png'); > const blob = await response.blob(); > > navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]) > .then(function () { console.log('copied'); }) > .catch(function (error) { console.log(error); }); > }); You need to initiate the write inside click event handler as in: document.getElementById("copy-html").addEventListener("click", event => { navigator.clipboard.write([ new ClipboardItem({ "text/png": async () => { const response = await fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'); return await response.blob(); } }), ]); });
(In reply to Ryosuke Niwa from comment #1) > (In reply to Felipe Ruiz from comment #0) > > I'm using javascript Clipboard API to copy an image to the clipboard. It > > works in Chrome and Edge but not in Safari in spite of official > > documentation of Safari says that it's supported. > > The issue is not so much async Clipboard API and the difference in the way > user activation is tracked between Blink and WebKit. > > > In this example (not my real code), write() throws an error: > > > > document.getElementById("copy").addEventListener("click", async function() { > > const response = await > > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/ > > PNG_transparency_demonstration_1.png'); > > const blob = await response.blob(); > > > > navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]) > > .then(function () { console.log('copied'); }) > > .catch(function (error) { console.log(error); }); > > }); > > You need to initiate the write inside click event handler as in: > > document.getElementById("copy-html").addEventListener("click", event => { > navigator.clipboard.write([ > new ClipboardItem({ > "text/png": async () => { > const response = await > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/ > PNG_transparency_demonstration_1.png'); > return await response.blob(); > } > }), > ]); > }); Hi Ryosuke, first of all, thanks for your reply. Unfortunately, I have tested your solution and I get the same error message.
> > You need to initiate the write inside click event handler as in: > > > > document.getElementById("copy-html").addEventListener("click", event => { > > navigator.clipboard.write([ > > new ClipboardItem({ > > "text/png": async () => { > > const response = await > > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/ > > PNG_transparency_demonstration_1.png'); > > return await response.blob(); > > } > > }), > > ]); > > }); > > > Hi Ryosuke, > > first of all, thanks for your reply. Unfortunately, I have tested your > solution and I get the same error message. Hi Felipe, I adapted the above code as a test case here: https://whsieh.github.io/examples/dice, and it seems to work in Safari on macOS with a couple of adjustments: - Changing the "text/png" above to "image/png". - Making the corresponding value for the "image/png" type a Promise instead of an async function. Please make sure that you're also testing in a secure context (https), where the clipboard API is available. Thanks! Wenson
<rdar://problem/74860840>
The different implementations unfortunately at the moment force developers to write code like this: ```js copyButton.addEventListener('click', async () => { try { // Safari treats user activation differently: // https://bugs.webkit.org/show_bug.cgi?id=222262. navigator.clipboard.write([ new ClipboardItem({ 'text/plain': new Promise(async (resolve) => { const svg = svgOutput.innerHTML; resolve(new Blob([svg], { type: 'text/plain' })); }), }), ]); } catch { // Chromium const svg = svgOutput.innerHTML; const blob = new Blob([svg], { type: 'text/plain' }); navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob, }), ]); } }); ``` Chromium is working on adding support for delayed generation of clipboard items (see https://crbug.com/1014310). At the same time it would be great if WebKit didn't expire the user activation.
*** Bug 244812 has been marked as a duplicate of this bug. ***