Click to Copy to Clipboard? Copy and Paste with JavaScript
By: Sam Ngu
Tags: JavaScript, ES6, Copy And Paste, Clipboard, Clipboard Api

Those “Click to Copy” buttons are voodoo magic, don’t you think so?

Also watch this on my YouTube Channel:

The mysterious magical click to copy button. Image by Author.

A lot of modern websites have this handy little button that conveniently copies content to our clipboard. I’ve always wondered how does it work behind the scene. Let’s take a deep look at it and see how we can achieve this.

Setting up

We will set up some HTML elements in the DOM just for demonstration. There are 2 elements, one is the content that we will copy to our clipboard, and the other one is the ‘click to copy’ button.

<article id="content-copy">

Copy this crap 💩.

</article> <button id="btn-copy">Copy</button>

They look like this in the DOM:

Image by Author.

Show me the code

Okay, here is what we are going to do. Firstly we will store the content-copy element as a variable. Then we will attach an event listener to the copy button, which contains the logic to copy the 💩 into our clipboard.

Now the bulk of the magic lies within the Clipboard API provided by the browser. Here’s the link: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API

const copyButton = document.getElementById('btn-copy'); copyButton.addEventListener('click', (event) => {

// getting the text content that we want to copy

const content = document.getElementById('content-copy').textContent; // loading the content into our clipboard

navigator.clipboard.writeText(content);

})

Reading Clipboard Content

The Clipboard API also offers us an easy way to read data from the clipboard. We will just need to call the readText() function from the clipboard object. The readText() function returns a promise , so we will need to call the then() function to retrieve our clipboard data.

navigator.clipboard.readText()

.then((copied) => {

console.log(copied);

});

But wait!

This alert box pops up right after we run the readText() function:

Oh no it is asking for permission! Image by Author.

By default, our browser prevents websites from reading clipboard content. This is a decision made for a number of security reasons. You see, we copied a lot of sensitive information to our clipboard in our daily life, eg. private messages, banking credentials, passwords and etc. If the browser lets any website freely read the content of our clipboard, imagine what kind of chaos would it bring to the internet? The important lesson here is to only allow permission from reputable websites.

Once we click on allow , we should be able to see our clipboard content in the console.

Pasting Image data

What about images? Does the browser handle them the same way as text data?

There are actually a few more steps required in order for us to work with images. Now let’s add a few more things to our DOM so we can paste image data to our webpage.

So our HTML would now look like this:

<article id="content-copy">

Copy this crap 💩.

</article> <button id="btn-copy">Copy</button>

<button id="btn-paste">Paste</button> <article id="content-paste"></article>

Now we will add the following to our JavaScript:

Store the Paste button as a variable. Store the content-paste article element as a variable. Attach an event listener to the paste button. When it is clicked, we will load the content of our clipboard into the content-paste article element. We use the read() function to retrieve the clipboard content as an array of ClipboardItem . The clipboard content is the first element in this array.

The clipboard content is an instance of ClipboardItem. The ClipboardItem interface offers us a number of helper functions that we can use to retrieve data in the clipboard.

At this point we are not really sure what kind of data is in the user’s clipboard. It could be text or image data. For now, we assume it is some image data. We will use the getType() function to attempt to read the clipboard as an image. The getType() function accepts an argument, which is the MIME type of the data. MIME is string format that details the file type of a particular data. You can read more about it here.

MIME string has this format: {data-type}/{extension} . In our case here, we attempt to read the clipboard content as png , so the MIME string will be 'image/png'. The getType() function will return us a promise which resolve to a blob representation of image data. Blob is an abbreviation for 'Binary Large Object', which is a fancy term for a giant string representing a file.

Our objective here is to put this Blob inside an image tag so we can show it in the DOM. The blob is actually stored in a temporary location in the browser, so we need to find a way to retrieve the URL directing to this blob . A way to do this is to use the createObjectURL() helper function in the URL object.

Once we got the blob URL, we can simply load it to an image element, and append it to pasteArticle .

If we failed to read the clipboard content as an image, the catch block will run, and we will attempt to read the clipboard content as text.

const pasteButton = document.getElementById('btn-paste'); const pasteArticle = document.getElementById('content-paste'); pasteButton.addEventListener('click', async (event) => { pasteArticle.textContent = ''; // using 'await' to easily resolve the result of the promise

const data = await navigator.clipboard.read(); // data is an array of clipboard items

// the actual clipboard content is in the first element.

const clipboardContent = data[0] // clipboardContent could be an image or text

try{

// assuming the clipboard content is an image

const imgBlob = await clipboardContent.getType('image/png') // retrieving the url for our blob

const blobUrl = window.URL.createObjectURL(imageBlob); // load the blob into an image tag

const img = document.createElement('img');

img.setAttribute('src', blobUrl); // append the image element to pasteArticle

pasteArticle.appendChild(img)

}catch(err){

console.log(err);

// clipboard has text data

// set pasteArticle to textContent

const text = await navigator.clipboard.readText();

pasteArticle.textContent = text;

} });

That’s it! The Clipboard API is actually quite simple to work with and less menacing than I originally thought.