Creating a Copy to Clipboard Button in React
Tags: react, hooks, javascript, webdev
Published: 2021-05-03 12:59:58

---
title: Creating a Copy to Clipboard Button in React
published: true
date: 2021-05-01 00:00:00 UTC
tags: #react #hooks #javascript #webdev
canonical_url: https://bionicjulia.com/blog/creating-copy-to-clipboard-button-in-react
description: With an animated copy success state for user feedback
---

I'm currently working on a social sharing module that I can place at the bottom of my React app screens. The idea is to allow visitors to share my link on their socials with a quick click of a social icon. In addition to the usual suspects of Facebook, Twitter and Instagram, I also wanted to include a "copy to clipboard" option for visitors that didn't necessarily want to post directly on a social platform. Here's a step by step on how I created a...

## Copy to clipboard button

My end goal was to have a component comprising an icon and text that reads "Copy link". Upon clicking on the component, the text should change to "Copied" and blink for a couple of seconds, before reverting back to "Copy link".

### Step 1 - Javascript logic

I had no idea how to effect a copy to clipboard action in Javascript before starting this build. Turns out it's not that hard, but you have to do it in a slightly roundabout way. Essentially, what's happening is that you need to:

- Create an `input` element in the DOM and set a value for it;
- Append the `input` element to the document body, which then allows you to select it;
- Run the `copy` command so that the value is now copied to clipboard; and
- Remove this temporary `input` element you've just been created, from the DOM.

```jsx
function copyToClipboard() {
  const tempInput = document.createElement('input');
  tempInput.value = 'https://bionicjulia.com/examplelink';
  document.body.appendChild(tempInput);
  tempInput.select();
  document.execCommand('copy');
  document.body.removeChild(tempInput);
}
```

### Step 2 - Create the React component

The next step is to bundle this logic up into a React component and hook it to an `onClick` event. I've called the function `copyToClipboard`.

One thing to note is that I added a conditional check to first assess whether a user's browser even supports the `copy` command in the first place. This is done with the `document.queryCommandSupported('copy')` statement. If it doesn't, this entire component would not work and thus should not render anything visible.

```jsx
export const CopyTextIcon: React.FC = () => {
  function copyToClipboard() {
    const tempInput = document.createElement('input');
    tempInput.value = 'https://bionicjulia.com/examplelink';
    document.body.appendChild(tempInput);
    tempInput.select();
    document.execCommand('copy');
    document.body.removeChild(tempInput);
  }

  return (
    <>
      {document.queryCommandSupported('copy') && (
        <div
          id="copy-icon"
          onClick={() => copyToClipboard()}
          className="cursor-pointer"
        >
          <div className="mt-8 flex justify-center">
            <img
              src={`${appConfig.publicUrl}/img/social/copy-mobile.svg`}
              alt="Copy"
            />
            <p className="ml-2 text-base-secondary text-sm light">Copy link</p>
          </div>
        </div>
      )}
    </>
  );
};
```

### Step 3 - Manage the copy text state

The next step was to manage the state of the "Copy link" text. To do this in React, I used the `useState` hook and coupled this with a timeout function within a `useEffect` hook.

```jsx
const [copySuccess, setCopySuccess] = useState('');

useEffect(() => {
  setTimeout(() => setCopySuccess(''), 2000);
}, [copySuccess]);
```

The other key step is to `setCopySuccess` state to `'Copied'` upon the `onClick` event.

```jsx
function copyToClipboard() {
  const tempInput = document.createElement('input');
  tempInput.value = 'https://bionicjulia.com/examplelink';
  document.body.appendChild(tempInput);
  tempInput.select();
  document.execCommand('copy');
  document.body.removeChild(tempInput);
  setCopySuccess('Copied');
}
```

To summarise what's happening here:

- The initial state of `copySuccess` is a blank string `''` ;
- Upon clicking the button, the `copySuccess` state is set to `'Copied'`;
- The `useEffect` hook kicks in and resets the `copySuccess` state to a blank string `''` after 2 seconds.

### Step 4: Animate the text

Finally, we hook up the "Copy link" text and make it dependent on the `copySuccess` state, and then add some blinking animation (I've called the class `blink`).

```jsx
return (
  <>
    {document.queryCommandSupported('copy') && (
      <div
        id="copy-icon"
        onClick={() => copyToClipboard()}
        className="cursor-pointer"
      >
        <div className="mt-8 flex justify-center">
          <img
            src={`${appConfig.publicUrl}/img/social/copy-mobile.svg`}
            alt="Copy"
          />
          <p className="ml-2 text-base-secondary text-sm light">
            {copySuccess ? (
              <span className="blink">{copySuccess}</span>
            ) : (
              'Copy link'
            )}
          </p>
        </div>
      </div>
    )}
  </>
);
```

Here's the simple CSS animation I created for the class.

```css
.blink {
  animation: blinker 1s linear infinite;
}

@keyframes blinker {
  50% {
    opacity: 0.2;
  }
}
```

And that's it! No need for any external libraries. 🤓 Is there a better way of doing this? Let me know on Twitter [@bionicjulia](https://twitter.com/bionicjulia)!