React-Markdown - How To Create a Copy Code Button
Tags: react
Published: 2022-06-05 02:33:42

Markdown is the markup language of choice for tech-savvy bloggers and publishing code samples is commonplace. When creating tutorials (such as this one), it's nice to have a quick way to copy a code block to the clipboard, instead of having to drag-select the code.

This tutorial will use two React libraries: `react-markdown` and `react-syntax-highlighter`.

We start with a component called `postBody`. This is responsible for rendering our markdown as HTML:

```js
import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { a11yDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
import CodeCopyBtn from './codeCopyBtn';

export default function PostBody({ content }) {
    // Add the CodeCopyBtn component to our PRE element
    const Pre = ({ children }) => <pre className="blog-pre">
        <CodeCopyBtn>{children}</CodeCopyBtn>
        {children}
    </pre>

    return (
        <ReactMarkdown
            className='post-markdown'
            linkTarget='_blank'
            rehypePlugins={[rehypeRaw]}
            remarkPlugins={[remarkGfm]}
            components={{
                pre: Pre,
                code({ node, inline, className = "blog-code", children, ...props }) {
                    const match = /language-(\w+)/.exec(className || '')
                    return !inline && match ? (
                        <SyntaxHighlighter
                            style={a11yDark}
                            language={match[1]}
                            PreTag="div"
                            {...props}
                        >
                            {String(children).replace(/\n$/, '')}
                        </SyntaxHighlighter>
                    ) : (
                        <code className={className} {...props}>
                            {children}
                        </code>
                    )
                }
            }}
        >
            {content}
        </ReactMarkdown>
    )
}
```

And then we'll create a component called `codeCopyBtn`:

```js
import React from "react";

export default function CodeCopyBtn({ children }) {
    const [copyOk, setCopyOk] = React.useState(false);

    const iconColor = copyOk ? '#0af20a' : '#ddd';
    const icon = copyOk ? 'fa-check-square' : 'fa-copy';

    const handleClick = (e) => {
        navigator.clipboard.writeText(children[0].props.children[0]);
        console.log(children)

        setCopyOk(true);
        setTimeout(() => {
            setCopyOk(false);
        }, 500);
    }

    return (
        <div className="code-copy-btn">
            <i className={`fas ${icon}`} onClick={handleClick} style={{color: iconColor}} />
        </div>
    )
}
```

And here's the CSS:

```css
.blog-pre {
    margin-bottom: 3em !important;
    -webkit-box-shadow: -10px 0px 13px -7px #000000, 10px 0px 13px -7px #000000, 35px -23px 2px -16px rgba(0, 0, 0, 0);
    box-shadow: -10px 0px 13px -7px #000000, 10px 0px 13px -7px #000000, 35px -23px 2px -16px rgba(0, 0, 0, 0);
    position: relative;
}

.code-copy-btn {
    color: white;
    position: absolute;
    right: 10px;
    top: -2px;
    font-size: 1.5em;
    cursor: pointer;
    transition: all 0.3s ease-in-out;
}

.code-copy-btn:hover {
    transform: scale(1.1);
    opacity: 0.9;
}
```

***

I hope you found this tutorial useful. Happy coding!

For more great information, please [Visit our Blog](https://designly.biz/blog).