GPTrush Logo

GPTrush

Start Building websites with GPTrush

Build any pages (Landing page, Blogs, Dashboard...) using AI in minutes.

How to Customize MDX Code Blocks in Next.js 14: Styling, Syntax Highlighting, and Copy to Clipboard Functionality

Welcome to Part 2 of our series on building a beautiful blog using Next.js 14, MDX, and TailwindCSS!

In our previous post, we explored how to set up a simple yet elegant blog structure.

Today, we'll take it a step further by customizing the styling of code blocks in your technical blog posts and adding a handy code copy button to enhance the reader experience.

NextJS MDX Code Block

What You’ll Learn:

  1. Creating a CodePre component to style MDX code blocks.
  2. Integrating this component into your MDX setup.
  3. Adding a copy-to-clipboard button to your code blocks.

1. Creating a CodePre Component

To style the code blocks generated from MDX, we'll create a CodePre component that customizes the pre tag. This component will be responsible for styling using TailwindCSS and functionalities like line numbers and copy-to-clipboard buttons.

Code Block
// components/CodePre.js
'use client'
import { useState, useRef } from 'react';

const Pre = ({ children }) => {
  const textInput = useRef(null);
  const [copied, setCopied] = useState(false);

  const onCopy = () => {
    setCopied(true);
    navigator.clipboard.writeText(textInput.current.textContent);
    setTimeout(() => {
      setCopied(false);
    }, 2000);
  };

  return (
    <div className="my-8 bg-zinc-900 rounded-lg border border-gray-700">
      {/* Toolbar/Header with Copy Button */}
      <div className="flex justify-between items-center p-2 bg-neutral-800 rounded-t-lg">
        <span className="text-xs font-semibold text-gray-400">Code Block</span>
        <button
          aria-label="Copy code"
          className={`h-8 w-8 rounded p-1 ${
            copied
              ? 'border-green-400 focus:border-green-400 focus:outline-none'
              : 'border-gray-600'
          }`}
          onClick={onCopy}
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            stroke="currentColor"
            fill="none"
            className={copied ? 'text-green-400' : 'text-gray-300'}
          >
            {copied ? (
              <>
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
                />
              </>
            ) : (
              <>
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
                />
              </>
            )}
          </svg>
        </button>
      </div>

      {/* Code Block */}
      <pre ref={textInput} >
        {children}
      </pre>
    </div>
  );
};

export default Pre;

2. Adding CodePre to mdx-components.js

Next, let’s integrate our CodePre component into the MDX setup by adding it to mdx-components.js. This will allow Next.js to use our custom component for rendering code blocks within MDX content.

Update your mdx-components.js as follows:

Code Block
// mdx-components.js
import Pre from '~/components/CodePre';
export function useMDXComponents(components) {
    return {
      pre: (props) => <Pre {...props} />,
      ...components,
    }
  }

This setup tells MDX to replace the default pre tags with our custom CodePre component whenever it encounters a code block (enclosed by triple backticks).

3. Adding Syntax Highlighting to MDX Code Blocks

To make your code blocks not only stylish but also more readable and attractive, adding syntax highlighting is essential. There are several popular libraries available that can help with this, including:

For this guide, we’ll use Highlight.js due to its simplicity and broad language support.

Step 1: Choose a Theme

First, you'll need to select a theme for your code blocks. Highlight.js offers a variety of themes that you can preview on their demo page . Pick a theme that fits the overall aesthetic of your blog.

Step 2: Download the CSS

Once you've chosen a theme, download the corresponding CSS file from the Highlight.js GitHub repository. For example, if you like the "VS2015" theme, download the vs2015.css file.

Step 3: Apply the Styles in Your Next.js Project

To apply the styles, you'll need to import the CSS file in your Next.js project. Depending on whether you want to style code blocks in specific posts or across all blog posts, you have two options:

a) For a specific blog post: Import the CSS directly in the page component of the blog post.

Code Block
// blog/firstpost/page.jsx
import FirstPost from '~/blogsrc/first.mdx';
import "~/styles/vs2015.css";  // Import the chosen Highlight.js theme CSS

export default function BlogPost({ source }) {
  return (
    <FirstPost />
  );
}

b) For all blog posts: Create a layout file (e.g., layout.jsx) in the /blog directory and import the CSS there. This will ensure the styles are applied globally across all blog posts.

Code Block
// /blog/layout.jsx
import "~/styles/vs2015.css";  // Import the chosen Highlight.js theme CSS

export default function MdxLayout({ children }) {
  return <>{children}</>;
}

Conclusion

With these steps, you now have a customized setup for styling and enhancing code blocks in your MDX-based blog posts using Next.js. By creating a CodePre component and integrating it with MDX, you can style your code blocks beautifully and add helpful features like copy-to-clipboard. This not only improves the look of your blog but also enhances the usability for your readers.

Stay tuned for the next part of our series, where we’ll dive deeper into further optimizing and customizing your Next.js blog setup!