608.620.5104 | info@tenforwardconsulting.com

How to add a "copy to clipboard" button to your website

Published September 17, 2018

The Challenge

I recently built an API for one of our major clients to allow their users to integrate their software with other services via Zapier. As part of that process, we created a step-by-step tutorial for those users, allowing them to customize their integrations. 

Much of the tutorial involves telling them what to type where, and rather than make them select everything individually, we wanted a way for them to copy the text automatically.


The Process

The internet suggested that the best way to set up the view was to house the text-to-be-copied in a "secret" input - ie: hiding the border and making it unclickable, so that it looked like normal text. 

Haml view

%h3.upcase Step 1: API Auth Token 

%div.js-copy-container 
  %input.js-text-to-copy{ readonly: true, value: api_auth_token } 
  %div.float-left= link_to "Copy", "#", class: "button js-copy-text-button"


I floated a "Copy" button to the right, and then set up my event listener in CoffeeScript. When "Copy" was clicked, I captured the value of the input, and sent it to the clipboard with an exec command (thanks for that tidbit, Stack Overflow!).

I also added an animation so that the button says "Copied!" for a few seconds before fading back to "Copy".

CoffeeScript

class ZapierPage
  constructor: ->
    $(document).ready @initListeners   
  
  initListeners: =>    
    $(".js-copy-text-button").on "click", @onCopyTextButtonClick 
  
  onCopyTextButtonClick: (ev) ->    
    ev.preventDefault()    
    $copyButton = $(ev.target)    
    $textToCopy = $copyButton.closest(".js-copy-container").find(".js-text-to-copy")     
    $textToCopy.select()    
    document.execCommand("copy")    
    $copyButton.html("Copied!")    
    
    setTimeout ->      
      $copyButton.html("Copy")    
    , 1000


So far, so good. 

And when I clicked "Copy", it did in fact copy the text to my clipboard - but it also selected the input. I tried around a million different things to try to prevent the selection, but nothing worked.


The Solution

With a little help from resident Ten Forward senior dev Brett, we added the following code right after the copy command:

    document.getSelection().removeAllRanges()    


An explanation why, via the MDN web docs:

The Selection.removeAllRanges() method removes all ranges from the selection, leaving the anchorNode and focusNode properties equal to null and leaving nothing selected.

Et voilá!

Author details

Hilary Stohs-Krause

Software developer
@hilarysk