How To Build a Code Block in ReactJS (With Syntax Highlighting)

How To Build a Code Block in ReactJS (With Syntax Highlighting)

April 17, 2023 - Edited on September 08, 2023

Adding Responsiveness

A great developer experience means ensuring our CodeBlock component looks good on all screen sizes. Let's make sure long lines of code wrap correctly or allow horizontal scrolling.

To enable scrolling, we can wrap our SyntaxHighlighter inside a div with overflow-x: auto:

export function CodeBlock({ language, code }: CodeBlockProps) {
  return (
    <div style={{ overflowX: 'auto' }}>
      <SyntaxHighlighter style={gruvboxDark} language={language}>
        {code}
      </SyntaxHighlighter>
    </div>
  );
}

Now, if the code is too long, users can scroll horizontally without breaking the layout!

Adding A Copy Button

A useful feature for developers is a copy-to-clipboard button. Let's add one to our CodeBlock component.

First, we'll use the navigator.clipboard API to copy text:

import { useState } from 'react';
import { Copy } from 'lucide-react'; // Import an icon for the button

export function CodeBlock({ language, code }: CodeBlockProps) {
  const [copied, setCopied] = useState(false);

  const handleCopy = async () => {
    await navigator.clipboard.writeText(code);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <div style={{ position: 'relative', overflowX: 'auto' }}>
      <button
        onClick={handleCopy}
        style={{ position: 'absolute', top: 10, right: 10 }}
      >
        {copied ? '✅ Copied!' : <Copy size={16} />}
      </button>
      <SyntaxHighlighter style={gruvboxDark} language={language}>
        {code}
      </SyntaxHighlighter>
    </div>
  );
}

Now, users can easily copy code snippets with a single click!

MDX Integrations

If you're using MDX in your Next.js project, you can integrate the CodeBlock component to render syntax-highlighted code directly in your markdown files.

In mdx-components.tsx, register the CodeBlock component:

import { CodeBlock } from './CodeBlock';

export const components = {
  pre: (props: any) => {
    const { children } = props;
    const code = children?.props?.children || '';
    const language = children?.props?.className?.replace('language-', '') || 'plaintext';
    return <CodeBlock language={language} code={code} />;
  },
};

Then, import and use it in next.config.mjs:

import { withMDX } from "@next/mdx";

export default withMDX({
  options: {
    remarkPlugins: [],
    rehypePlugins: [],
  },
});

With this setup, code blocks in your .mdx files will automatically use CodeBlock for syntax highlighting!

Resources

Happy coding! 🚀