Implementing a Syntax Highlighter in React
––– views
3 min read
The highlighter you will get is the one that you see belo, feel free to change the color scheme to match your style.
From your CMS you will receive the code values which you need to pass on to the component.
TS
<CodeBlockfileName={fileName} // received from CMSlanguage={language} // received from CMScode={code} // received from CMS/>
The two functions I use useCopyToClipboard and getLanguageFormatted can be found below.
TS
import React from "react";import Highlight, { Prism } from "prism-react-renderer";import { FaCopy } from "react-icons/fa";import vsDark from "prism-react-renderer/themes/vsDark"import { useCopyToClipboard } from "../lib/hooks/useCopyToClipboard";export const CodeBlock = ({ code, language, metastring = "", fileName }) => {const [isCopied, handleCopy] = useCopyToClipboard(1000, code);const { languageFormatted, color } = getLanguageFormatted(language);return (<Highlight Prism={Prism} code={code} language={language} theme={vsDark}>{({ className, style, tokens, getLineProps, getTokenProps }) => (<div className={`relative not-prose my-10 `}><preclassName={`rounded-xl relative overflow-hidden bg-slate-800 ${className}`}style={style}><div className="relative flex text-xs leading-6 "><div className="flex items-center px-4 pt-1 mt-2 border-t border-b border-t-transparent border-b-slate-400 w-full justify-between"><pclassName={`bg-zinc-800} h-full pt-2 pb-2 px-4`}><span className={color}>{JSON.stringify(languageFormatted).replace(/['"]+/g, "").toUpperCase()}</span>{" "}<span className="text-current">{fileName}</span></p><buttonclassName={`hidden md:inline-block group mb-2 mr-1 ${isCopied ? "text-secondary" : "text-gray-400"}`}onClick={() => handleCopy()}><span className="sr-only">Copy code</span><FaCopy /></button></div></div><div className="relative w-auto p-5 overflow-auto prose text-gray-300 prose-full-width text-sm md:text-md"><span>{tokens.map((line, i) => {const lineProps = getLineProps({ line, key: i });return (<div key={i} {...lineProps}>{line.map((token, key) => (<span key={key} {...getTokenProps({ token, key })} />))}</div>);})}</span></div>{/* Show fade on side of codeblock if content overflows */}<div className="absolute w-8 top-[45px] right-0 bg-gradient-to-l from-midnight code-fade"></div></pre></div>)}</Highlight>);};export default CodeBlock;
It takes language as an arg and returns a nicely formatted version of it along with the color.
TS getLanguageFormatted.ts
const getLanguageFormatted = (language) => {let color, languageFormatted;switch (language) {case "javascript":languageFormatted = "JS";color = "text-yellow-500";break;case "typescript":languageFormatted = "TS";color = "text-blue-400";break;case "css":languageFormatted = "CSS";color = "text-blue-400";break;case "markup":languageFormatted = "HTML";color = "text-orange-600";break;default:languageFormatted = language;color = "text-secondary";break;}return {languageFormatted,color,};};
Copies everything from the code snippet to user’s clipboard
TS useCopyToClipboard.ts
import { useCallback, useEffect, useState } from 'react';import copy from 'copy-to-clipboard';// By default will copy URL to clipboard if text is not passed to the hook.export function useCopyToClipboard(resetInterval = 3000, text = null) {const [isCopied, setCopied] = useState(false);const handleCopy = useCallback(() => {if (window !== undefined) {copy(text ?? window.location.href);setCopied(true);}}, []);useEffect(() => {let timeout;if (isCopied && resetInterval) {timeout = setTimeout(() => setCopied(false), resetInterval);}return () => {clearTimeout(timeout);};}, [isCopied, resetInterval]);return [isCopied, handleCopy] as const;}
That’s all the pieces you need to display code nicely on your website, if you want to see an implentation of this with Notion, check out the code-repo of my website.
To comment please authenticate