If you’re reading this blog post, there’s a very good chance you’ve probably cloned a git repository from GitHub. One of the small but mighty features GitHub added to its site allows users to click a button to copy the Git URL to your clipboard so that you can easily paste it into your terminal to clone the repository to your local machine.
This is a lot easier than having to select the entire line of text, then click Control+C
or Command+C
to copy it. It also prevents you from missing any characters of the URL when you select it.
Now, let’s say you’re building a new blog website for yourself and you want to make it as easy as possible for readers to share a post with someone. Some social media sites offer ways to use a link and automatically start a new post on their site, but not every app supports that kind of functionality.
What if you want to copy a URL and send it to someone over Zoom or iMessage? It would greatly improve the user experience if we gave users a button to copy the text. It would also be especially helpful for mobile users.
In this post, I’m going to show you how to accomplish this by creating a reusable React component that will accept the text as a prop value, and, on click, will copy the text to the user’s clipboard.
Thankfully, in the age of modern web development, we’re afforded many useful web APIs that make tasks like copying and pasting text in the browser easy. The current de-facto API for clipboard interaction is the Clipboard API, which provides a few simple functions you can use for both copying text to the user’s clipboard and reading items from it.
Unfortunately, not all web browsers support this API as of the time of writing. While some browsers fully or partially support it, Internet Explorer doesn’t support it at all.
However, there is a legacy function you can use as a backup if you still have to support IE, using document.execCommand('copy')
.
Here is an example of a function that accepts text as an argument and copies it to the user’s clipboard:
export async function copyTextToClipboard(text) { if ('clipboard' in navigator) { return await navigator.clipboard.writeText(text); } else { return document.execCommand('copy', true, text); } }
Now, let’s walk through this.
First, we have an asynchronous function called copyTextToClipboard
, which has a single argument text. It checks if the property clipboard exists on the navigator
object. This is an easy way to check if the current browser supports the Clipboard API.
Next, if the browser supports the Clipboard API, we wait for the promise navigator.clipboard.writeText(text)
to be resolved and return it.
Otherwise, we call the Document.execCommand
function with the argument 'copy', true, text
. You can read about the arguments of this command in the MDN Docs.
When you run this command in a browser, it will copy whatever text is passed in as a parameter to the user’s clipboard, so that when the user pastes the text, it will appear.
Now that we have a simple working function for this, we’re going to implement it into a flexible React component.
Let’s start by setting up a simple React component that visually represents what we’re trying to achieve:
function ClipboardCopy({ copyText }) { const [isCopied, setIsCopied] = useState(false); // TODO: Implement copy to clipboard functionality return ( <div> <input type="text" value={copyText} readOnly /> <button> <span>{isCopied ? 'Copied!' : 'Copy'}</span> </button> </div> ); }
Here, I’ve set up the component ClipboardCopy
, which accepts the property copyText
. This will be the text that we want our users to have copied. It will render a read-only <input>
element that displays our copyText
string and a button that we’ll use to execute our copy function.
I’ve also added the state value isCopied
to keep track of whether the text has been copied to the clipboard and change the text shown on our copy
button.
Now, we need to create an onClick
handler function for our button that will asynchronously call our copyToClipboard
function and pass copyText,
as an argument.
Based on the result of the function, we will either change the state of isCopied
to true
, or, if an error occurs, we’ll print it to the console. If the command is successful, the next time the user pastes text on their device, the value of copyText
will be the result.
function ClipboardCopy({ copyText }) { const [isCopied, setIsCopied] = useState(false); // This is the function we wrote earlier async function copyTextToClipboard(text) { if ('clipboard' in navigator) { return await navigator.clipboard.writeText(text); } else { return document.execCommand('copy', true, text); } } // onClick handler function for the copy button const handleCopyClick = () => { // Asynchronously call copyTextToClipboard copyTextToClipboard(copyText) .then(() => { // If successful, update the isCopied state value setIsCopied(true); setTimeout(() => { setIsCopied(false); }, 1500); }) .catch((err) => { console.log(err); }); } return ( <div> <input type="text" value={copyText} readOnly /> {/* Bind our handler function to the onClick button property */} <button onClick={handleCopyClick}> <span>{isCopied ? 'Copied!' : 'Copy'}</span> </button> </div> ); }
I’ve added a new function, handleCopyClick
, which serves as the onClick
event handler for our button element.
When the user clicks the button, the event handler function is executed, and our asynchronous function copyTextToClipboard
is executed.
Once the function is resolved, it either sets the isCopied
state value to true
or, if an error occurs, prints the error.
I’ve also added a setTimeout
function that resets the copied state value back to false
after 1.5 seconds. This allows us to give the user some interaction feedback because copying text to a clipboard is a “background task” that doesn’t provide any inherent feedback.
Now, we can use this component anywhere in our React app, like so:
function App() { return ( <div className="App"> <ClipboardCopy copyText="https://google.com" /> <ClipboardCopy copyText="https://logrocket.com" /> </div> ); }
Finally, when you run the app, this is what your user should see:
You can improve this solution by providing better feedback in the case of an error in calling copyTextToClipboard
. If you have an error component in your project, you could call a function or change the state to display an error to the user, rather than print text to the console that the user will most likely never see.
Don’t want to manually write the component that implements the copy and reading to clipboard functionality? Well, there are open-source alternatives that you can use. Let’s check some of them out.
React-copy-to-clipboard is a React component that allows you to copy text to your clipboard. It’s based on the JavaScript copy-to-clipboard npm package which, unlike our previous example, uses the experimental ClipboardData API, which is supported in most browsers.
It’s also straightforward to use. First, you’ll need to install the component by running npm install react-copy-to-clipboard
on your terminal. Now you can use the component, as shown below:
import "./styles.css"; import { CopyToClipboard } from "react-copy-to-clipboard"; export default function App() { return ( <div className="App"> <h1>Clipboard Copy</h1> <CopyToClipboard text="text" onCopy={() => alert("Copied")}> <span>Copy to clipboard with span</span> </CopyToClipboard> </div> ); }
The component accepts a text
and an onCopy
prop. The text prop allows you to set the text you intend to copy, while the onCopy
prop is an event that fires when a copy activity is carried out successfully. In our example, we use the native JavaScript alert. In a real application, use something that is less intrusive, like Snackbar.
useCopy
React HookuseCopy
is a React Hook that lets you copy text into your user’s clipboard. It uses the copy-to-clipboard JavaScript library we discussed earlier, which means it does not use the Clipboard API. Instead, it uses the Clipboard Data API.
Implementation is smooth, just the way you’d normally use React Hooks. Install the plugin by running npm install useCopy
on your terminal, import the useCopy
Hook and use it like so:
import React from "react"; import useCopy from "use-copy"; export default function App() { const [copied, copy, setCopied] = useCopy("https://logrocket.com, this is the text to copy"); const copyText = () => { copy(); setTimeout(() => { setCopied(false); }, 3000); }; return ( <div> {copied ? "Copied to clipboard" : <a onClick={copyText}>Copy text</a>} </div> ); }
By default, the copied state variable is set to false
until the copy
function is called. Then, we can reset the status back to false
after three seconds to allow the user to copy again.
It might also interest you to see how we implement this library. I’ve extracted the code from the project’s GitHub repository so you can see how elegant it is:
import copyToClipboard from 'copy-to-clipboard'; import { useState, useRef, useEffect, useCallback } from 'react'; export default function useCopy(str: string): [boolean, () => void, (value: boolean) => void] { const copyableString = useRef(str); const [copied, setCopied] = useState(false); const copyAction = useCallback(() => { const copiedString = copyToClipboard(copyableString.current); setCopied(copiedString); }, [copyableString]); useEffect(() => { copyableString.current = str; }, [str]); return [copied, copyAction, setCopied]; }
Now that we’ve covered the JavaScript Clipboard API, you can see how easy it is to implement it into whatever your use case is, or even consider a third-party library if you choose. This improves the user experience in your application, and, of course, making it simple for users to share your content can also increase your site exposure if you are trying to gain an audience for your content. After reading this, I hope you can reap these benefits for yourself!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
One Reply to "Implementing copy-to-clipboard in React with Clipboard API"
Wow Daniel, I appreciate how well you explained everything! Maureen Jones