JavaScript
Article
By Craig Buckler

Roll Your Own Copy to Clipboard Feature in 20 Lines of JavaScript

By Craig Buckler

Using the OS clipboard is a basic IT skill. As a developer, you’ve learned that tab, Ctrl/Cmd+A, Ctrl/Cmd+C followed by Ctrl/Cmd+V will highlight, copy and paste in an instant.

Life is less easy for regular users. Even if a user knows what the clipboard is, those with 20:20 vision and cat-like reflexes can struggle to highlight the exact text they want. The copying process is rarely intuitive if they don’t know keyboard shortcuts, can’t see the hidden browser Edit menu, have never used a right-click menu or don’t know about long-hold options on touch-screens.

Perhaps we could help everyone by offering one-click “copy to clipboard” buttons? That would be useful for even the quickest keyboard-happy power user!

Clipboard Security

A few years ago it was impossible for browsers to directly use the clipboard. Developers had to resort to Flash applets to provide basic functionality.

The clipboard seems innocuous but imagine what could happen if a browser was able to view and manipulate the content at will. It would be possible for scripts (including third-party ones) to peek at the text and post passwords, sensitive information or even whole documents to a remote server.

Today, basic clipboard integration is possible but there are limitations:

  1. Most browsers support the clipboard but forget Safari on Mac and iOS.
  2. Support varies across browsers and some features are incomplete or buggy.
  3. The user must initiate an event such as clicking a mouse button or pressing the keyboard. A script cannot arbitrarily use the clipboard at any time.

document.execCommand()

The key method is document.execCommand() which can be passed 'cut', 'copy' or 'paste'. We’ll concentrate on document.execCommand('copy') since it’s the most useful option.

Before using it, we should check whether the browser supports the command copying using either document.queryCommandSupported('copy'); or document.queryCommandEnabled('copy'); (yes, that’s two methods which do the same thing). Unfortunately, both return false in Chrome even though it’s supported. We could check the availability of document.execCommand but the most viable option is to wrap document.execCommand('copy') in a try-catch block.

Next, what should we allow the user to copy? Our script must highlight text and all browsers permit textual input and textarea fields to be selected using the select() method. Firefox and Chrome/Opera also support document.createRange which allows text to be selected from any element, e.g.

// select text in #myelement node
var
  myelement = document.getElementById('#myelement'),
  range = document.createRange();

range.selectNode(myelement);
window.getSelection().addRange(range);

However, this isn’t supported in IE/Edge.

--ADVERTISEMENT--

clipboard.js

If you’ve given up all hope of implementing a robust cross-browser clipboard solution, clipboard.js can ease the pain. It has several options such as HTML5 data attributes which identify an activation trigger and which element will be copied, e.g.

<input id="copyme" value="text in this field will be copied" />
<button data-clipboard-target="#copyme">copy</button>

Roll Your Own

clipboard.js is a mere 2Kb but we can implement a solution in less than twenty lines of code if we’re happy to accept the following criteria:

  • only appropriate form fields can be copied
  • it’ll fail in some browsers (I’m looking at you Safari) but we can highlight the input text and show a message advising the user to press Ctrl/Cmd + C.

Like clipboard.js, we’ll create an activation trigger button which has a data attribute (data-copytarget) pointing at an element to copy (#website):

<input type="text" id="website" value="http://www.sitepoint.com/" />
<button data-copytarget="#website">copy</button>

A self-executing function can attach a click event handler which parses any data-copytarget attributes, selects the field’s text and runs document.execCommand('copy'). If this fails, the text remains selected and the advise alert box is displayed:

(function() {

  'use strict';

  // click events
  document.body.addEventListener('click', copy, true);

  // event handler
  function copy(e) {

    // find target element
    var
      t = e.target,
      c = t.dataset.copytarget,
      inp = (c ? document.querySelector(c) : null);

    // is element selectable?
    if (inp && inp.select) {

      // select text
      inp.select();

      try {
        // copy text
        document.execCommand('copy');
        inp.blur();
      }
      catch (err) {
        alert('please press Ctrl/Cmd+C to copy');
      }

    }

  }

})();

Demonstration:

See the Pen JavaScript clipboard integration by SitePoint (@SitePoint) on CodePen.

This demonstration has styling and a “copied” animation which takes it over twenty lines of code but that’s optional.

Summary:

  1. Use the .select() method to select the contents of the form element you wish to copy
  2. Call the document.execCommand("copy") method
  3. Call the .blur() method to remove focus from the form element
  4. Wrap steps 2 & 3 in a try catch block to cater for non-compliant browsers

Other Uses

You may be able to devise other novel clipboard integration features. For example, when hovering your mouse over any card in Trello.com, you can press Ctrl/Cmd+C and that card’s URL is copied to the clipboard. In the background, the application creates a hidden form element containing the URL then selects and copies it. Useful and clever — although I suspect few users know about the feature!

Please share your ideas with others below.

  • Jack Scotty

    This will be useful to my dev and I at work in our company’s web-based app. You are correct, without this article I’d have had no idea this feature existed. Thanks!

  • This is a very useful option. I’m glad it’s becoming available with native support instead of having to rely to tricks like the Flash object. Especially that today Flash is virtually dead on mobile devices.

  • M S i N Lund

    Doesn’t seem to work on iPad.

    The “copied”-message is shown, but noting gets copied

    • Craig Buckler

      It’s not supported on any Apple product (mentioned above). That said, the try-catch should catch that so no “copied” message is shown?

      • M S i N Lund

        Nope it doesn’t.

        But

        if (document.execCommand(‘copy’)) {

        …works

        • Craig Buckler

          So, Safari doesn’t support this feature but doesn’t fail when it’s run. Great. Thanks Apple – as if development wasn’t complex enough!

  • It’s cool to see options like this becoming available for anyone with a JS API. Now, we have to hope that the support will be better in a near future…

  • Browser support still seems to be spotty but it’s better than it used to be. I had to deal with this problem a couple years ago when I was building a Docbook XML editor and CMS for a publishing company. I needed cut/copy/paste buttons and it was more of pain than it should have been. Good to see this working on Firefox and Chrome without needing a signed script or a browser extension.

    • Craig Buckler

      It works in IE/Edge too. Just waiting for a certain fruity vendor now…

      • Vinsar12

        Works in Windows Phone 10 – Edge too!

  • Trevor

    Here’s a simple, small option that works in at least the latest versions of Chrome, Firefox, and Edge: http://codepen.io/trevorhreed/pen/pyLwXZ?editors=1010

    405 bytes compressed:

    function copyText(e){function t(e){if(document.selection){var t=document.body.createTextRange();t.moveToElementText(e),t.select()}else if(window.getSelection){var t=document.createRange();t.selectNode(e),window.getSelection().removeAllRanges(),window.getSelection().addRange(t)}}var n=document.createElement(“DIV”);n.textContent=e,document.body.appendChild(n),t(n),document.execCommand(“copy”),n.remove()}

  • Can some one guide me how do i use this code to get use in wordpress post? Thanks.

  • Exactly what I was looking for, short and simple, the only problem I’ve encountered si that the “copied” animation in Firefox 45.0.1 stops working randomly.
    Here’s a gif animation of the “bug”.

    http://i.imgur.com/uvB88kD.gif

    I was testing the script, here, on JSFiddle and on a website of mine, clicking on the copy button works and I get the confirmation from the animation but sometimes, at completely random times, clicking again on the button would not fire the “copied” animation, despite that the text get copied with success anyway.

    On Chrome everything works as expected.

    Any idea why?

    Thanks

  • Safari 10 includes programmatic cut and copy support 🙌

    https://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html “Use JavaScript commands to programmatically cut and copy text to the clipboard with document.execCommand(‘cut’) and document.execCommand(‘copy’).”

  • vurso

    Nice exactly what I was after (needed a place to start so I can roll my own)

  • Bill Hannah

    There’s a small error in the above code. In the current version of Safari (9.1.1), the exception isn’t thrown. However, the document.exec() call will return false if it fails (which it does in Safari).

    I have made an updated pen at http://codepen.io/billhannah/pen/qNXJkA that works in Safari 9.1.1

    • Craig Buckler

      Thanks Bill.

  • rahaponsel

    Thanks

  • Camilo

    Hi Guys, I’m quite struggled if I have to copy text from more than 1
    input fields, on my case I’ve got a form with 5 input text, and I’d need
    to use the submit button to save a record on the DB and then the value
    of the 5 fields would be copied over the clipboard as per the below
    format:

    “Input Text value 1 – Input Text value 2 – Input Text value 3 – Input Text value 4 – Input Text value 5”

    Any ideas would be really appreciated.

  • In the Roll Your Own section, you write:


    c = t.dataset.copytarget,
    inp = (c ? document.querySelector(c) : null);

    Just to clarify, I don’t think this will work as shown. Namely, the querySelector method will fail. Rather, I think it should be:

    inp = (c ? document.querySelector(`[data-copytarget='${c}']`) : null);

    In the argument to the querySelector method, I’m using backticks and interpolate the value of the data-copytarget attribute. Let me know if I’m missing something…

    • Craig Buckler

      `c` holds the value held in the `data-copytarget` attribute, e.g. `#twitter`. That’s a standard CSS selector which can be passed to document.querySelector.

      Does the demo work in your browser? If not, which one are you using?

      • Ahh, I just noticed you’re giving the data attribute a CSS selector as a value. That’s awesome, I’ve never seen that pattern before. My mistake.

  • Zen StandFastForTruth

    Brilliant code and layout. …. This is something I have looked for, for far too long. ……………….. Is there a SIMPLE Demo file, as disentangling the code from this webpage is a mammoth task for an amateur. ……….. I am trying to build a Men’s Healing Group here in the UK, and want to partly fund it by selling junk on the internet ( recycling! ). …………. With so many damaged Men, perhaps they can each be given some component to carry out as therapy, which requires SIMPLE tools. ………………….. Programmers love to cram a thousand brilliant ideas on one webpage, but this swamps the mind of those less developed ………….Zen, Brighton UK ……….. zen4men@hotmail.com

    • Zen StandFastForTruth

      I downloaded the webpage, and found file:///SITEPOINT____001_files/vNvEwE(1).html. ……………. Works perfectly! …………… KISS – Keep It Superbly Simple …

  • There are some errors in this description, though. First of all, document.queryCommandSupported and document.queryCommandEnabled are not the same thing at all.
    queryCommandSupported indicates whether or not a particular command is available at all and can be used anywhere within a JavaScript whereas queryCommandEnabled indicates whether or not the command in question can actually be invoked in the current context (returns true if and only if inside an event handler triggered by user interaction and it makes sense to execute the command, false otherwise). Second, queryCommandSupported and queryCommandEnabled can be detected by means of feature sniffing and without having to resort to a try … catch block.

    if(document.queryCommandSupported && document.queryCommandSupported(“copy”))
    {
    do something
    }
    else
    {
    do something else
    }

    This permits implementing the copy feature in JavaScript when the browser’s command API is present and the requested command is available and allows for indicating alternatives if not.

Recommended
Sponsors
Get the latest in JavaScript, once a week, for free.