DevZone Logo

Create "Copy Code" button for React-Markdown

FS

MD Fahid Sarker

Senior Software Engineer · July 7, 2024


-
-
Share
Bookmark

Markdown is awesome for creating blog sites like DevZone. It allows you to write content in a simple and readable format. However, when it comes to code snippets, it's often useful to provide a "Copy Code" button for users to easily copy the code to their clipboard.

Preview

Step 1: Get started with React-Markdown

Create a basic component to render the markdown content using the react-markdown library.

Code.tsx
export async function MarkdownRenderer({ content }: { content: string }) { return ( <Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}> {content} </Markdown> ); }

Step 2: Add Syntax Highlighting to Code Blocks

The next step is to add the code function the components prop. This function will render the code blocks with syntax highlighting using a library like react-syntax-highlighter or anything else you like. For more info on this, check out the react-syntax-highlighter package.

Code.tsx
... <Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]} components={{ code({ node, inline, className = "blog-code", children, ...props }: any) { const match = /language-(w+)/.exec(className || ""); return !inline && match ? ( <SyntaxHighlighter style={nightOwl} PreTag="div" language={match[1]} {...props} > {String(children).replace(/\n$/, "")} </SyntaxHighlighter> ) : ( <code className={cn(className, "bg-slate-200 px-1 rounded")} {...props} > {children} </code> ); }, }} > {content} </Markdown> ...

Step 3: Create a CopyAble Component

We now need to create a component that can take another component as a parameter and add a "Copy" button to it. The principal of the component is very simple - it will take a children prop and a toCopy prop. The children prop will be the component that we want to add the "Copy" button to, and the toCopy prop will be the text that we want to copy to the clipboard.

Code.tsx
const CopyAble = ({ children, toCopy, }: { children: React.ReactNode; toCopy: string; }) => { const [copied, setCopied] = useState(false); const copyCode = () => { navigator.clipboard.writeText(toCopy); setCopied(true); }; return ( <div className="relative"> <div className="absolute right-1 top-1 text-white hover:text-black hover:bg-white rounded cursor-pointer" onClick={copyCode} > {copied ? ( <CheckIcon className="m-1 text-green-200 hover:text-green-600" size={18} /> ) : ( <CopyIcon className="m-1 " size={18} /> )} </div> {children} </div> ); };

Step 4: Wrap the SyntaxHighlighter Component with CopyAble

Simply wrap the SyntaxHighlighter component with the CopyAble component in the code function. Pass the code snippet as the toCopy prop - String(children).replace(/\n$/, ""). Note that this is the same code snippet that we are rendering in the SyntaxHighlighter component.

Code.tsx
... const match = /language-(w+)/.exec(className || ""); return !inline && match ? ( <CopyAble toCopy={String(children).replace(/\n$/, "")}> <SyntaxHighlighter style={nightOwl} PreTag="div" language={match[1]} {...props} > {String(children).replace(/\n$/, "")} </SyntaxHighlighter> </CopyAble> ) : ( <code className={cn(className, "bg-slate-200 px-1 rounded")} {...props}> {children} </code> ); ...

Final Code

After following all the steps, this is how the final code should look.

Code.tsx
export async function MarkdownRenderer({ content }: { content: string }) { return ( <Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]} components={{ code({ node, inline, className = "blog-code", children, ...props }: any) { const match = /language-(w+)/.exec(className || ""); return !inline && match ? ( <CopyAble toCopy={String(children).replace(/\n$/, "")}> <SyntaxHighlighter style={nightOwl} PreTag="div" language={match[1]} {...props} > {String(children).replace(/\n$/, "")} </SyntaxHighlighter> </CopyAble> ) : ( <code className={cn(className, "bg-slate-200 px-1 rounded")} {...props} > {children} </code> ); }, }} > {content} </Markdown> ); }
Found the blog helpful? Consider sharing it with your friends.
Buy Me a Coffee

ReactMarkdownReact-markdownCopy-codeMarkdown-codeTypeScriptReact

Related Blogs

Blogs that you might find interesting based on this blog.