How to easily copy text to clipboard with JavaScript

- 4 min read

When HTML added “design mode” for What You See Is What You Get (WYSIWYG) editing, a simple way to copy text to the device’s clipboard was introduced.

Recently, I’ve ran into multiple scenarios where copying information from a web page to the device’s clipboard has been needed. In the old days, this required use of ActiveX or Flash (or a similar process on the device that was available to the web page). However, with the relatively recent wide adoption of document.execCommand() this has become a trivial problem to solve cross browser.

First up, the code:

var tmp = document.createElement("textarea");
tmp.value = "The string that you want in the clipboard goes here";
tmp.style.height = "0";
tmp.style.overflow = "hidden";
tmp.style.position = "fixed";
document.body.appendChild(tmp);
tmp.focus();
tmp.select();
document.execCommand("copy");
document.body.removeChild(tmp);

Note, this isn’t necessarily the most robust solution, however it is perfect and simple for copying plain text to the clipboard (and can include line breaks). If the item you’re looking to copy needs to include HTML structure, images, etc there’s an experimental technology called Selection API that you’ll need to work with, rather than a simple <textarea>.

Second note, I’ve written the code in this post to work for the vast majority of browsers in the wild at time of authoring with no assumption of transpiling. If you’re using a transpiler or only support modern browsers, it would be good practice to change all instances of var to const/let (as appropriate).

Explanation of the copy to clipboard code

First a textarea element is created and a value is applied to it. This value can be any string:

var tmp = document.createElement("textarea");
tmp.value = "The string that you want in the clipboard goes here";

Next, put the textarea within the body of the HTML document so that it can be focused/selected by the user’s browser.

document.body.appendChild(tmp);

Then focus, the textarea, select all of its text, and copy the text.

tmp.focus();
tmp.select();
document.execCommand("copy");

Lastly, remove the textarea. Note this happens so quickly you don’t need to hide the textarea with CSS since the user will never see it on the page.

document.body.removeChild(tmp);

A note about document.execCommand(“copy”)

Most browsers’ security features do not allow a page to copy data to the clipboard without the user taking an action (such as clicking on a button). Keep this in mind if you’re attempting to copy information to the clipboard without the user taking any action.

Example, bind button click to copy a block of code

<code id="a-code-snippet">
    // Copy title and URL of page (without query string/hash).
    console.log(document.getElementsByTagName("title")[0].textContent);
    console.log(document.location.origin + document.location.pathname);
</code>
<button class="copy-element-text" data-copy-from="#a-code-snippet">
    Copy code
</button>
<script>
    // Note, if you were going to put this code straight on a site, you should
    // wrap it with a self-executing function to avoid polluting global scope.
    //
    // It looks like this:
    // (function () {
    //   /* paste JavaScript here */
    // })();

    // Once we have the element we want to copy from, copy to clipboard.
    function copyTextFromEl(el) {
        var tmp = document.createElement("textarea");
        tmp.value = el.textContent;
        // Prevent text area from briefly being visible.
        tmp.style.height = "0";
        tmp.style.overflow = "hidden";
        // Fixed prevents browser from scrolling to the textarea (if it is
        // outside the current view).
        tmp.style.position = "fixed";
        document.body.appendChild(tmp);
        tmp.focus();
        tmp.select();
        document.execCommand("copy");
        document.body.removeChild(tmp);
    }

    // Handle click event on bound button.
    function clickListener(e) {
        // Using currentTarget ensures the user actually clicked on the button.
        // Events in JavaScript bubble and currentTarget ensures you receive the
        // button element your event listened for clicks on.
        var btn = e.currentTarget;
        // Since we're dealing with DOM which could be manipulated by other code
        // on the page, it is best to ensure the property that's expected exists
        // and that it was able to find the copy-from target.
        //
        // If you're unfamiliar with data-* attributes, they can be accessed from
        // JavaScript using the dataset object. Hyphens in the HTML are removed
        // and the property name is converted to camel case.
        //
        // Thus "data-copy-from" is accessed as "btn.dataset.copyFrom"
        if ("copyFrom" in btn.dataset) {
            var copyEl = document.querySelector(btn.dataset.copyFrom);
            if (copyEl) {
                copyTextFromEl(copyEl);
            }
        }
    }

    // App binding to all buttons with copy-element-text class.
    //
    // While our example only has one button, selecting all instances on the
    // page and adding listeners to each, establishes a re-usable feature on the
    // page.
    var buttons = document.querySelectorAll("button.copy-element-text");
    for (var i = 0; i < buttons.length; i++) {
        buttons[i].addEventListener("click", clickListener);
    }
</script>

Author

Cody Craven enjoys sharing tidbits of information that he learns through his life-long journey developing websites and configuring web servers.

When at work, Cody can often be found banging his head against his keyboard for hours days weeks-on-end trying to solve technical issues that would otherwise prevent his teammates from creating Member value at AAA.

All content that Cody contributes to this site are his own ideas and do not necessarily represent AAA's positions or opinions.