A couple of days ago I implemented a feature to allow viewers on my website to easily copy code blocks on my website. Personally, it is quite a useful feature
for a technical blog.
In this article, I'm going to share how you can implement the same for your sites – applicable to all React-based sites.
useCopyableRef
hook
Thanks to React hook functionality, I've encapsulated the logic into an easily understandable and reusable hook:
import { useRef, useState } from "react"; import copyToClipboard from "copy-to-clipboard"; // You'll need this package: `yarn add copy-to-clipboard`. const useCopyableRef = <T extends HTMLElement = HTMLElement>( delay: number = 4 * SECONDS // You may want to change this to 4000, or define SECONDS somewhere in your application. ) => { const ref = useRef<T>(null); const [isCopied, setCopied] = useState(false); const copy = () => { if (isCopied) return; if (!ref.current) throw new Error("Ref is nil."); copyToClipboard(ref.current.textContent || ""); setCopied(true); setTimeout(() => setCopied(false), delay); }; return { ref, isCopied, copy }; }; export default useCopyableRef;
It's simple, right?
Usage in UI components
useCopyableRef
is similar to useRef
, additionally, it returns isCopied
and copy
props, which you'd need to implement your UI components.
Implementing your UI components can be as simple as the following example:
import useCopyableRef from "~/hooks/useCopyableRef"; const CodeBlock = (props: React.HTMLProps<HTMLPreElement>) => { const { ref, isCopied, copy } = useCopyableRef<HTMLPreElement>(); return ( <> <pre ref={ref} {...props} /> <button onClick={copy} disabled={isCopied}> {isCopied ? "Copied!" : "Copy"} </button> </> ); }; export default CodeBlock;
That's it, don't forget to style your components however you want to!