On any given web page it’s not uncommon to copy a piece of text, such as a paragraph, code snippet, or a URL. And to do so, users first have to select the text, then use either the menu in the browser (the contextual menu) or keyboard shortcut to copy the selected content.
However, as far as UX is concerned, we can streamline the process if it’s likely to happen often. In Github, for example, there’s a button to copy the repository URL.

In Bit.ly, you will find a similar one to copy the short URL. This button is really handy for users to copy a piece of content that is expressly meant to be copied.

Owing to browser restrictions, adding such functionality used to be a real hassle. Most developers had to resort to a library dependant on Flash, like Clippy, for example. Fortunately now we have a JavaScript library that allows us to implement it much more easily. It’s called Clipboard.js, and in this beginner’s tutorial I’ll teach you how to effectively deploy it.
Installation
To install Clipboard.js to your web project, download the file, place it in a suitable folder within your website directories, and link it in the document. Alternately, we can load it from the hosted file in CDN, so add this to the bottom of your HTML page:
<script src="//cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.4.0/clipboard.min.js"></script>
Now we need two elements in our document. First is the target which holds the content we want to copy. The target element could be, for example, an input
(with an ID) containing a short URL:
<input id="post-shortlink" value="https://ac.me/qmE_jpnYXFo">
The second element is the trigger. This element, in our case, is a button. The trigger element must use the data attribute data-clipboard-target
, whose value points to the target element through its ID:
<button class="button" id="copy-button" data-clipboard-target="#post-shortlink">Copy</button>
Once these elements are in place, turn Clipboard.js on by adding this within script tags, or in a separate JavaScript file:
(function(){ new Clipboard('#copy-button'); })();
Bingo! We should now be able to copy the shortened URL in the input element by clicking on the button.
Going Advanced
In some cases, adding an ID, class and the data-*
attribute to the target elements of our content is not feasible — something that could happen when dealing with lots of legacy content as well as multiple target elements.
As an example, let’s say we have a website whose content comprises paragraphs and a number of code snippets. We’ll use PrismJS, a fantastic library to display code with properly highlighted syntax. PrismJS does not come with the “copy” utility, so we’ve decided to do that with Clipboard.js. But, the problem is, we have hundred of pages throughout our website with that kind of content.
This is where the Clipboard.js APIs come into play.
Looking into the APIs
Clipboard.js presents a couple of events, success
and error
, which respectively allow us to identify whether it has effectively copied the content, or failed. The error
would likely occur in Safari as it does not support the copy/cut command from the execCommand method that Clipboard.js relies upon.
Furthermore, these events also return the following Properties:
action
: return the action we aim at the target element. This will return eithercopy
orcut
text
: only returned upon thesuccess
event. It returns the text that has been copied or cut from the target element.trigger
: returns the element which triggered thecopy
or thecut
action.
These APIs enable us to implement Clipboard.js into our content without directly modifying its wrapping elements. In our case, we can use them to add the “copy” utility to the code snippets in our legacy content.
Clipboard.js + PrismJS
At this point, we should have PrismJS already setup (download the files to your project folder, reference the JavaScript in your document). In our page markup, each of the code snippets is wrapped in a pre
and code
element with a language-{name}
class name. In this example we’re using LESS code, so we have it added with the class language-less
, as follows:
<pre><code class="language-less">@bg: transparent; .element {& when not (@bg = transaprent) { background: @bg; } }</code></pre>
Adding the Copy Button
We now have to include a button in each pre
element to copy the respective code. To begin with, we get all the pre
tags within the content by selecting them using the getElementsByTagName
method.
var pre = document.getElementsByTagName('pre');
We most likely have two or more pre
tags within the content, so we need to loop through each the pre
we've selected.
for (var i = 0; i < pre.length; i++) { }
Within the for
loop, add the following lines to include the button.
for (var i = 0; i < pre.length; i++) { var isLanguage = pre[i].children[0].className.indexOf('language-'); if ( isLanguage === 0 ) { var button = document.createElement('button'); button.className = 'copy-button'; button.textContent = 'Copy'; pre[i].appendChild(button); } }
Let’s recap the code. We first validate whether we have a code
element added with the language-
prefixed class. If that’s not the case, we won’t include the button.
So we add the button in the pre
element. Each button is set with a class,copy-button
, and “Copy” text, as shown below:
<pre><code class="language-less">@bg: transparent; .element {& when not (@bg = transparent) { background: @bg; } }</code><button class="copy-button">Copy</button></pre>
It should now be visible in each code snippet:

Run Clipboard
Now we run Clipboard, so each button copies the code by setting the target element to the previous element relative to the trigger, .copy-button
. In our case, this element is the code
.
var copyCode = new Clipboard('.copy-button', { target: function(trigger) { return trigger.previousElementSibling; } });
We now have the button functioning. As you click the button, it should copy the code snippet. But let’s go a little bit further by working with the custom events.
Working with the Custom Events
Let’s imagine we want to make the copy experience more interactive for our users. As the user has clicked the button, and it has successfully copied the code, we would like to change the button text from “Copy” to “Copied”. To do so, add the following:
copyCode.on('success', function(event) { event.clearSelection(); event.trigger.textContent = 'Copied'; window.setTimeout(function() { event.trigger.textContent = 'Copy'; }, 2000); });
The above code does three things:
- First, we clear selection within the area of the copied content using the
clearSelection()
utility function from Clipboard. Adding this is optional. - Then we set the content to “Copied”
- Lastly, we revert it back to “Copy” after two seconds.
In case of an error where execCommand
is not supported, like in Safari (at the time of writing), we change the the button text to 'Press “Ctrl + C” to copy' instead. Add the following code:
copyCode.on('error', function(event) { event.trigger.textContent = 'Press "Ctrl + C" to copy'; window.setTimeout(function() { event.trigger.textContent = 'Copy'; }, 2000); });
That’s it! We now have a fully functioning and interactive copy button. The remaining task we have here is to style the button, but I will leave that entirely up to you.
Wrapping Up
Clipboard.js is a handy JavaScript library that has make adding the copy utility to web pages much less complicated. In this tutorial, we looked into the basics, then some advanced stuff with the exposed APIs and the custom events.
Clipboard.js relies on Selection and the execCommand so it will only work in browsers where these two methods are supported: Chrome 42, Firefox 41, Internet Explorer 9, and Opera 9. As mentioned, Safari users are currently out of luck.
Finally, I hope you enjoyed the tutorial and don't forget the demo.