DEV Community

Bionic Julia
Bionic Julia

Posted on • Originally published at bionicjulia.com on

Creating a Copy to Clipboard Button in React

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.
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);
}
Enter fullscreen mode Exit fullscreen mode

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.

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>
      )}
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

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.

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

useEffect(() => {
  setTimeout(() => setCopySuccess(''), 2000);
}, [copySuccess]);
Enter fullscreen mode Exit fullscreen mode

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

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');
}
Enter fullscreen mode Exit fullscreen mode

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).

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>
    )}
  </>
);
Enter fullscreen mode Exit fullscreen mode

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

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

@keyframes blinker {
  50% {
    opacity: 0.2;
  }
}
Enter fullscreen mode Exit fullscreen mode

And that's it! No need for any external libraries. 🤓 Is there a better way of doing this? Let me know on Twitter @bionicjulia!

Latest comments (0)