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
inputelement in the DOM and set a value for it; - Append the
inputelement to the document body, which then allows you to select it; - Run the
copycommand so that the value is now copied to clipboard; and - Remove this temporary
inputelement 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);
}
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>
)}
</>
);
};
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]);
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');
}
To summarise what's happening here:
- The initial state of
copySuccessis a blank string''; - Upon clicking the button, the
copySuccessstate is set to'Copied'; - The
useEffecthook kicks in and resets thecopySuccessstate 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>
)}
</>
);
Here's the simple CSS animation I created for the class.
.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!
Top comments (0)