skip to Main Content

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 NotAllowedError: Invalid Blob types. Am I missing something?

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


  1. This Chrome error message sticks out as funky:

    NotAllowedError: Invalid Blob types.

    I think you need to use new Blob() to create your clipboard text:

    const input = document.querySelector('input')
    
    async function copy() {
      const type = 'text/plain'
      const blob = new Blob([input.value], {type})
      const cbi = new ClipboardItem({[type]: blob})
      await navigator.clipboard.write([cbi])
      console.log(`Copied: ${input.value}`)
    }
    
    <input type="text" value="Some text..."/>
    <button onclick="copy()">Copy</button>
    

    This should work in Safari, Chrome and Edge. For Firefox, keep the one-liner.

    Login or Signup to reply.
  2. 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.

     navigator.clipboard.writeText(text).then(function() {
    
            //do something here if you want, like inform the user that some text has been copied to clipboard
    
      }, function(err) {
    
            console.log('Could not copy to clipboard');
    
     });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search