I’m trying to write text to the clipboard when a user selects an option from a dropdown menu. The following works for all browsers except Safari:
<select onChange="writeTextToClipboard(this.value);">
<option value="Text I want to copy">Copy to clipboard</option>
</select>
function writeTextToClipboard(value) {
navigator.clipboard.writeText(value);
}
I understand that Safari expects a Promise to be passed to the write
function of the clipboard object, so following this blog post, I modified my code:
async function writeTextToClipboard(value) {
// Safari, Chrome
if(typeof ClipboardItem && navigator.clipboard.write) {
const type = 'text/plain'
const blob = new Blob([value], {type})
const cbi = new ClipboardItem({[type]: blob})
await navigator.clipboard.write([cbi])
console.log(`Copied: ${value}`)
}
// Firefox
else {
navigator.clipboard.writeText(value);
}
}
This still throws a NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
on Safari and also breaks on Chrome with Am I missing something?NotAllowedError: Invalid Blob types.
I’m on Safari 17.0
EDIT, 25.10.2023: I fixed the issue on Chrome, but it still doesn’t work on Safari. I’ve created a fiddle with a minimal example.
I also realized that my example works when it’s called in the onClick
handler of a button instead of onChange
of a select element. I clarified my use-case.
2
Answers
This Chrome error message sticks out as funky:
I think you need to use
new Blob()
to create your clipboard text:This should work in Safari, Chrome and Edge. For Firefox, keep the one-liner.
There is one gotcha with permissions that had me scratching my head some time ago when I was trying the same…in Safari the webpage has to be served over https! Won’t do nothing over plain old "http" or launching a local html file://
The following definitely works in Safari for simple text copy (over https) and as you’ve said it has to be a promise.