document.execCommand('copy') not working on Chrome

38,380

Solution 1

I am not really clear as to what really happens here...

It seems there is a mismatch as to what should be used between the value and the textContent properties of your textarea.
Chrome seems to always use value, while Firefox uses textContent.

btn.onclick = e => {
  const txt = document.createElement('textarea');
  document.body.appendChild(txt);
  txt.value = 'from value'; // chrome uses this
  txt.textContent = 'from textContent'; // FF uses this
  var sel = getSelection();
  var range = document.createRange();
  range.selectNode(txt);
  sel.removeAllRanges();
  sel.addRange(range);
  if(document.execCommand('copy')){
    console.log('copied');
  }
  document.body.removeChild(txt);
}
<button id="btn">Copy!</button>
<textarea>You can paste here

</textarea>

Since chrome doesn't look at the textContent property, Range#selectNodeContents will select nothing on this browser...

However, you can use Range#selectNode which should return the same result in this case, and will workaround the issue.

document.getElementById('btn').addEventListener('click', function(){
  var textarea = document.createElement('textarea');
  textarea.textContent = 'copied text';
  document.body.appendChild(textarea);

  var selection = document.getSelection();
  var range = document.createRange();
//  range.selectNodeContents(textarea);
  range.selectNode(textarea);
  selection.removeAllRanges();
  selection.addRange(range);

  console.log('copy success', document.execCommand('copy'));
  selection.removeAllRanges();

  document.body.removeChild(textarea);
  
})
<button id="btn">copy</button>
<textarea>You can paste here</textarea>

Solution 2

For people reading this question in 2020, if you're having trouble with document.execCommand('copy'), you may want to try using the Clipboard API.

Per Mozilla:

There are two ways browser extensions can interact with the system clipboard: the Document.execCommand() method and the modern asynchronous Clipboard API.

Also per Mozilla, document.execCommand() is now obsolete:

This feature is obsolete. Although it may still work in some browsers, its use is discouraged since it could be removed at any time. Try to avoid using it.

With the Clipboard API, writing text to the clipboard is particularly easy:

const textToCopy = 'Hello there!'
navigator.clipboard.writeText(textToCopy)
  .then(() => { alert(`Copied!`) })
  .catch((error) => { alert(`Copy failed! ${error}`) })

More info:

Mozilla's discussion of the two clipboard systems

Google's discussion of the two clipboard systems

Another good discussion of the Clipboard API

CanIUse

Solution 3

I have found that you can't dynamically insert a input field, insert some text, and then copy it to the clipboard. I was able to copy text from an existing input tag.

Share:
38,380
Jake
Author by

Jake

Developer and Sysadmin - mostly for webapps. Python/Django, Javascript/Backbone/Jquery.

Updated on July 12, 2022

Comments

  • Jake
    Jake almost 2 years

    On Chrome only document.execCommand('copy') returns true but does not copy the text, it clears the clipboard.

    I can't find anyone who's had the same problem, there are a lot of similar questions but please don't mark this as a duplicate unless it really is.

    • I am calling selection.removeAllRanges() before selection.addRange().
    • selection.getRangeAt(0).cloneContents() returns a fragment containing the correct text
    • The text in the textarea doesn't appear selected
    • If I call textarea.select() before document.execCommand('copy') the text appears selected and gets coppied to the clipboard. I don't want to do this because it focuses the textarea and causes the page to scroll.
    • Tested on Chrome 61 and 63, MacOS
    • Working in Safari

    Here's my code (used within a click event listener)
    https://codepen.io/jakecr/pen/XVXvKz

    var textarea = document.createElement('textarea');
    textarea.textContent = 'coppied text';
    document.body.appendChild(textarea);
    
    var selection = document.getSelection();
    var range = document.createRange();
    range.selectNodeContents(textarea);
    selection.removeAllRanges();
    selection.addRange(range);
    
    // DOESN'T WORK WITHOUT THIS
    // textarea.select();
    
    console.log(selection.getRangeAt(0).cloneContents());
    console.log('copy success', document.execCommand('copy'));