This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Bojan Jagetic
Introduction
Creating a Code Block
with the ability to Copy to Clipboard
in React
When displaying code snippets on a website or application, it's often useful to provide a way for users to quickly copy the code to their clipboard. In this tutorial, we'll show you how to add this functionality to a code block created with the react-syntax-highlighter library, using clipboard.js and react-icons with tailwindcss for styling.
Prerequisites
Before we get started, make sure you have the following libraries installed:
- react-syntax-highlighter for syntax highlighting
- react-copy-to-clipboard for copying to the clipboard
- react-icons for the copy icon
- tailwindcss for styling
- react-toastify for sending toast messages
You can install these packages by running the following command in your project's root directory:
npm install react-syntax-highlighter clipboard react-icons tailwindcss
or
yarn add react-syntax-highlighter clipboard react-icons tailwindcss
NOTE I am using all this modules in my specific case, for my blog/portfolio website (you can check there how it looks in real example) but you do not have to use all of this, also you can use similar modules like clipboard.js or react-hot-toast for example.
Import Required Libraries
At the top of your component file, import the libraries you'll need:
import React, { useState } from 'react'
import SyntaxHighlighter from 'react-syntax-highlighter'
import { IoIosCopy, IoIosCheckmarkCircleOutline } from 'react-icons/io'
import { vs2015 } from 'react-syntax-highlighter/dist/cjs/styles/hljs'
import { ToastContainer, toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
import { CopyToClipboard } from 'react-copy-to-clipboard'
You have variation of themes for react-syntax-highlighter depending if you are using hljs
or prisma
. Here you can find all available themes for hljs and for prisma.
Create the Code Block Component
In the component that will display the code block, create a functional component called CodeBlock
that takes in a code prop.
const CodeBlock = ({ code }) => {
//...
return (
<div>
{/* code block and button goes here */}
</div>
);
};
Create the Copy to Clipboard Button
In the CodeBlock component, create a button that the user can click to initiate the copy action. It should include the FaClipboard icon and classes from tailwindcss that position the button in the top right corner of the code block.
return (
<div className="relative">
<button
className="absolute flex flex-row top-0 right-0 p-2">
<span className='m-1 pb-1 basis-3/4 text-xs'>{language}</span>
<CopyToClipboard text='Hello World !'>
</CopyToClipboard>
</button>
</div>
)
In this example, relative and absolute classes from tailwindcss are used to position the button with the FaClipboard icon in the top-right corner of the code block. The p-2 class is for padding and flex flex-row are used to position language name next to copy to clipboard icon.
Adding functionalities
In most cases we will have different values to copy and different languages, in this case we will use variable for code and language properties. Also you will maybe want to show toast message to user that code is copied in this example we will use react-toastify
, so lets expand our code with copy functionality, language and code variables.
Using variables
So we have provided code to our CodeBlock
now we want to pass it to our SyntaxHighlighter
and CopyToClipboard
where we will copy it to the clipboard.
const CodeBlock = ({ code, language }) => {
const notify = () => {
toast(<ToastDisplay className='bg-neutral-700 m-2' />)
}
function ToastDisplay () {
return (
<div className='m-2'>
<p className='text-md'>Copied to clipboard !</p>
</div>
)
};
}
Add syntax highlighter component
Now that you have the button, we want to show our code which will be copied, for this we are using react-syntax-highlighter component to which we will pass our code.
return (
<div className="relative">
<button
className="absolute flex flex-row top-0 right-0 p-2">
<span className='m-1 pb-1 basis-3/4 text-xs'>javascript</span>
<CopyToClipboard text={code}></CopyToClipboard>
</button>
<SyntaxHighlighter
className=''
language='javascript'
style={vs2015}
wrapLines={true}
wrapLongLines={true}
showLineNumbers={false}
showInlineLineNumbers={false}
>
{code}
</SyntaxHighlighter>
</div>
)
Sending toast
After we successfully copy we want to notify and let end user know that code is successfully copied to clipboard.
const CodeBlock = ({ code, className }) => {
const notify = () => toast(<ToastDisplay className='bg-neutral-700 m-2' />)
function ToastDisplay () {
return (
<div className='m-2'>
<p className='text-md'>Copied to clipboard !</p>
</div>
)
};
return (
<div className="relative">
<button
className="absolute flex flex-row top-0 right-0 p-2">
<span className='m-1 pb-1 basis-3/4 text-xs'>{language}</span>
<CopyToClipboard text={code}
onCopy={() => notify()}>
<IoIosCopy className="text-lg m-1 basis-1/4 hover:text-white" />
</CopyToClipboard>
</button>
<SyntaxHighlighter
className=''
language={parseLanguageByClass(className)}
style={vs2015}
wrapLines={true}
wrapLongLines={true}
showLineNumbers={false}
showInlineLineNumbers={false}
>
{code}
</SyntaxHighlighter>
<ToastContainer
position="bottom-right"
autoClose={5000}
hideProgressBar
newestOnTop={false}
closeOnClick={false}
closeButton={false}
limit={1}
rtl={false}
pauseOnFocusLoss={false}
draggable={false}
pauseOnHover={false}
theme="dark" />
</div>
)
}
Change icon after copying
This one is optional as well, you can use it but if you don't like it just skip this step. As seen on many examples and websites, I like more to have icon changed after code is copied, so initially we have copy icon and after it gets copied we will change it to checkmark icon which will last for 5 seconds and after that it will be reverted back to copy icon.
const [copied, setCopied] = useState(false)
const notify = () => {
toast(<ToastDisplay className='bg-neutral-700 m-2' />)
copy()
}
...
const copy = () => {
console.log('Copied!')
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 5000)
}
return (
<div className="relative">
<button
className="absolute flex flex-row top-0 right-0 p-2">
<span className='m-1 pb-1 basis-3/4 text-xs'>{language}</span>
<CopyToClipboard text={code}
onCopy={(copied) => notify()}>
{copied
? <IoIosCheckmarkCircleOutline className="text-lg m-1 text-green-500 basis-1/4 " />
: <IoIosCopy className="text-lg m-1 basis-1/4 hover:text-white" />}
</CopyToClipboard>
...
)
Conclusion
That's All Folks, we have the whole component up and running. If you had problem catching up, here you can check the whole code :
import React, { useState } from 'react'
import SyntaxHighlighter from 'react-syntax-highlighter'
import { IoIosCopy, IoIosCheckmarkCircleOutline } from 'react-icons/io'
import { vs2015 } from 'react-syntax-highlighter/dist/cjs/styles/hljs'
import { ToastContainer, toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
import { CopyToClipboard } from 'react-copy-to-clipboard'
const CodeBlock = ({ code, language }) => {
const [copied, setCopied] = useState(false)
const notify = () => {
toast(<ToastDisplay className='bg-neutral-700 m-2' />)
copy()
}
function ToastDisplay () {
return (
<div className='m-2'>
<p className='text-md'>Copied to clipboard !</p>
</div>
)
};
const copy = () => {
console.log('Copied!')
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 5000)
}
return (
<div className="relative">
<button
className="absolute flex flex-row top-0 right-0 p-2">
<span className='m-1 pb-1 basis-3/4 text-xs'>{language}</span>
<CopyToClipboard text={code}
onCopy={(copied) => notify()}>
{copied
? <IoIosCheckmarkCircleOutline className="text-lg m-1 text-green-500 basis-1/4" />
: <IoIosCopy className="text-lg m-1 basis-1/4 hover:text-white" />}
</CopyToClipboard>
</button>
<SyntaxHighlighter
className=''
language={language}
style={vs2015}
wrapLines={true}
wrapLongLines={true}
showLineNumbers={false}
showInlineLineNumbers={false}
>
{code}
</SyntaxHighlighter>
<ToastContainer
position="bottom-right"
autoClose={5000}
hideProgressBar
newestOnTop={false}
closeOnClick={false}
closeButton={false}
limit={1}
rtl={false}
pauseOnFocusLoss={false}
draggable={false}
pauseOnHover={false}
theme="dark" />
</div>
)
}
export default CodeBlock
You can check final look on my personal blog or you can check video example how this really look
Remember, there is many different variation on this topic, you can use whatever module you like in order to look how you imagined. Its pretty straight-forward solution and easy to implement, but if you have any doubts or questions feel free to contact me.
This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Bojan Jagetic
Bojan Jagetic | Sciencx (2023-01-12T16:07:07+00:00) One-Click Code Block Copying in React with react-copy-to-clipboard. Retrieved from https://www.scien.cx/2023/01/12/one-click-code-block-copying-in-react-with-react-copy-to-clipboard/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.