62

I'm making an extension for Google Chrome and I have hit a snag.

I need to copy a readonly textarea's content to the clipboard on click in the popup. Does anyone know the best way to go about this with pure Javascript and no Flash? I also have jQuery loaded in the extension, if that helps any. My current (non-working) code is...

function copyHTMLCB() {
$('#lb_html').select();
$('#lb_html').focus();
textRange = document.lb_html_frm.lb_html.createTextRange();
textRange.execCommand("RemoveFormat");
textRange.execCommand("Copy");
alert("HTML has been copied to your clipboard."); }
Kyle Ross
  • 2,090
  • 4
  • 20
  • 27

11 Answers11

68

All credit goes to joelpt, but in case anyone else needs this to work in pure javascript without jQuery (I did), here's an adaptation of his solution:

function copyTextToClipboard(text) {
  //Create a textbox field where we can insert text to. 
  var copyFrom = document.createElement("textarea");

  //Set the text content to be the text you wished to copy.
  copyFrom.textContent = text;

  //Append the textbox field into the body as a child. 
  //"execCommand()" only works when there exists selected text, and the text is inside 
  //document.body (meaning the text is part of a valid rendered HTML element).
  document.body.appendChild(copyFrom);

  //Select all the text!
  copyFrom.select();

  //Execute command
  document.execCommand('copy');

  //(Optional) De-select the text using blur(). 
  copyFrom.blur();

  //Remove the textbox field from the document.body, so no other JavaScript nor 
  //other elements can get access to this.
  document.body.removeChild(copyFrom);
}
tom_mai78101
  • 2,383
  • 2
  • 32
  • 59
Jeff Gran
  • 1,585
  • 15
  • 17
  • It helps me a lot!. Thank you so much to take the time to make it again in plane js. – LogoS May 11 '15 at 14:07
  • 2
    why not simply `document.body` instead of `var body = document.getElementsByTagName('body')[0];`? – jscripter Jul 07 '15 at 22:37
  • @jscripter I updated the code (via editing it). Now waiting for peer reviews. – tom_mai78101 May 22 '18 at 15:25
  • I wondered why it did not worked for me, but then I found that permissions must be set "clipboardWrite" or "clipboardRead" depending what we do with clipboard... – John Boe Jun 27 '18 at 16:24
  • @tom_mai78101 Why `document.body.removeChild(copyFrom)` ? Why not do `copyFrom.remove()` ? Isn't it eaiser? – Shayan Mar 20 '20 at 08:11
  • 1
    @Shayan I was preserving the original author's code, and wasn't really looking into improving the code. The code was originally written in 2013. – tom_mai78101 Mar 20 '20 at 23:08
  • I am using this in the app I'm currently developing and no problems so far. – DeZeA Jan 09 '21 at 12:49
  • Thank you - this worked for me on a custom extension I made in the background script. – Cody Jul 09 '21 at 13:58
  • `execCommand` is deprecated – Bawantha Mar 24 '22 at 22:27
  • 1
    For folks migrating to Manifest v3 on their browser extensions... None of these answers will work, not even the clipboard API, [within the service worker JavaScript](https://stackoverflow.com/a/61977696/48700), usually called the background script in Manifest v2. You can still write to the clipboard using most of these options when called from the user's active tab via injected scripts, your extension's pop-up scripts, or the extension options page scripts, though, where you are operating in the context of an active HTML document. – patridge Sep 22 '22 at 14:12
43

I found that the following works best, as it lets you specify the MIME type of the copied data:

copy: function(str, mimeType) {
  document.oncopy = function(event) {
    event.clipboardData.setData(mimeType, str);
    event.preventDefault();
  };
  document.execCommand("copy", false, null);
}
Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
gjuggler
  • 501
  • 5
  • 8
  • Actually after you use this function you simply can't copy anything else from the page. I believe it is because of the preventDefault() thing. – g.a Jul 19 '23 at 13:55
22

I'm using this simple function to copy any given plaintext to the clipboard (Chrome only, uses jQuery):

// Copy provided text to the clipboard.
function copyTextToClipboard(text) {
    var copyFrom = $('<textarea/>');
    copyFrom.text(text);
    $('body').append(copyFrom);
    copyFrom.select();
    document.execCommand('copy');
    copyFrom.remove();
}

// Usage example
copyTextToClipboard('This text will be copied to the clipboard.');

Due to the fast append-select-copy-remove sequence, it doesn't seem to be necessary to hide the textarea or give it any particular CSS/attributes. At least on my machine, Chrome doesn't even render it to screen before it's removed, even with very large chunks of text.

Note that this will only work within a Chrome extension/app. If you're using a v2 manifest.json you should declare the 'clipboardWrite' permission there; this is mandatory for apps and recommended for extensions.

joelpt
  • 4,675
  • 2
  • 29
  • 28
19

The Clipboard API is now supported by Chrome, and is designed to replace document.execCommand.

From MDN:

navigator.clipboard.writeText(text).then(() => {
    //clipboard successfully set
}, () => {
    //clipboard write failed, use fallback
});
Kartik Soneji
  • 1,066
  • 1
  • 13
  • 25
6

You can copy to clipboard using Experimental Clipboard API, but it is available only in the dev branch of a browser and not enabled by default (more info)..

Anthony Raymond
  • 7,434
  • 6
  • 42
  • 59
serg
  • 109,619
  • 77
  • 317
  • 330
  • 7
    broken link, any new sources? – Victor S Jul 10 '12 at 00:46
  • 5
    This is no longer true - it just needs extension permissions for clipboardRead and -Write. The current (jQuery) best solution appears to be here http://stackoverflow.com/a/7147192/1129420 – iono Aug 18 '12 at 06:37
  • 3
    Documentation link is dead –  Mar 13 '16 at 05:42
  • @DimaFomin That's for Chrome Web Apps to copy/paste image data, instead you want [developer.chrome.com/extensions/declare_permissions](https://developer.chrome.com/extensions/declare_permissions) for Chrome Extensions, and it seems that link is the only place where `clipboardRead` and `clipboardWrite` are both mentioned. – tom_mai78101 May 22 '18 at 15:16
  • The Clipboard API is no longer experimental, please see [my answer](https://stackoverflow.com/a/59695008/7370354) for details. – Kartik Soneji Jan 11 '20 at 13:53
  • 1
    Obsolete answer, this is now possible and better solutions are available on the thread. OP should consider unmarking this as an accepted answer. – DeZeA Jan 09 '21 at 12:48
3

You can't copy a read only bit of text using execCommand("Copy"), it has to be an editable text area. The solution is to create a text input element and copy the text from there. Unfortunately you can't hide that element using display: none or visibility: hidden as that will also stop the select/copy command from working. However, you can 'hide' it using negative margins. Here's what I did in a Chrome Extension popup that obtains a short url. This is the bit of the code that re-writes the popup window with the shorturl (quick and dirty approach ;-)):

document.body.innerHTML = '<p><a href="'+shortlink+'" target="_blank" >'+shortlink+'</a><form style="margin-top: -35px; margin-left: -500px;"><input type="text" id="shortlink" value="'+shortlink+'"></form></p>'
document.getElementById("shortlink").select()
document.execCommand("Copy") 
atomicules
  • 2,155
  • 25
  • 24
2

Only this worked for me.

document.execCommand doesn't work at all for chrome as it seems to me.

I left execCommand in the code, but probably for one simple reason: So that this shit just was there :)

I wasted a lot of time on it instead of going through my old notes.

    function copy(str, mimeType) {
        document.oncopy = function(event) {
            event.clipboardData.setData(mimeType, str);
            event.preventDefault();
        };
        try{            
            var successful = document.execCommand('copy', false, null);
            var msg = successful ? 'successful' : 'unsuccessful';
            console.log('Copying text command was ' + msg);
            if (!successful){
                navigator.clipboard.writeText(str).then(
                    function() {
                        console.log('successful')
                    }, 
                    function() {
                        console.log('unsuccessful')
                    }
                );
            }
        }catch(ex){console.log('Wow! Clipboard Exeption.\n'+ex)}
    }
Garric
  • 591
  • 3
  • 10
1

I read somewhere that there are security restrictions with Javascript that stops you from interacting with the OS. I've had good success with ZeroClipboard in the past (http://code.google.com/p/zeroclipboard/), but it does use Flash. The Bitly website uses it quite effectively: http://bit.ly/

pinksy
  • 301
  • 4
  • 14
1
let content = document.getElementById("con");
content.select();
document.execCommand("copy");

The above code works completely fine in every case. Just make sure the field from which you are picking up the content should be an editable field like an input field.

webcrawler
  • 79
  • 1
  • 5
0

I had a similar problem where I had to copy text from an element using only javascript. I'll add the solution to that problem here for anyone interested. This solution works for many HTML elements, including textarea.

HTML:

    <textarea id="text-to-copy">This is the text I want to copy</textarea>
    <span id="span-text-to-copy">This is the text I want to copy</span>

Javascript:

let textElement = document.getElementById("text-to-copy");

//remove selection of text before copying. We can also call this after copying
window.getSelection().removeAllRanges();

//create a Range object
let range = document.createRange();

//set the Range to contain a text node.
range.selectNode(textElement);

//Select the text node
window.getSelection().addRange(range);

try {
    //copy text
    document.execCommand('copy');
} catch(err) {
    console.log("Not able to copy ");
}

Note that if you wanted to copy a span element for instance, then you could get its text node and use it as a parameter for range.selectNode() to select that text:

let elementSpan = document.getElementById("span-text-to-copy");
let textNode = elementSpan.childNodes[0];
jakobinn
  • 1,832
  • 1
  • 20
  • 20
0

I'm trying to create a chrome extension that would copy data straight into the clipboard on button click, but I couldn't find any relevant info regarding this; tried a lot of stuff from different threads around here.

I found an extension that automatically copies text after selecting it, but it doesn't work for me

This plugin doesn't work for me but if I paste its code into my own extension, it works just fine

window.addEventListener(
    'mouseup',
    () => {
        const content = document.getSelection()?.toString();
        if (!content) { return; }

        navigator.clipboard.writeText(content);
    },
    false
);
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 08 '22 at 04:34