CY is here.

Highlight Lines in Code Block with Prism.js and MDX

The Needs

There are blogs, websites, and online documents that have their code block with some lines highlighted. As in the screenshot below.

Screenshot: code block with highlighting lines
Screenshot: code block with highlighting lines

I always want to implement this cool thing for my own blog which is made of Next.js and MDX. I use Prism.js for highlighting the syntax of the code block. However, I couldn't find a way to enable its Line Highlight plugin.

The Flawed Way

My old approach was calling Prism in useEffect:

// This is the blog post layout component
import Prism from "prismjs";

const BlogPost = (props) => {
	useEffect(() => {
		if (typeof window !== "undefined") {
			Prism.highlightAll()
		}
	}, []);

	return (
		// omitted
	)
}

This approach cannot implement line highlight (at least not that I am aware of).

The Right Way

After a VERY LONG time of research, I finally discovered a solution: instead of using prismjs with next-mdx-remote, we can use rehype-prism-plus with next-mdx-remote.

As the next-mdx-remote official document says when we serialize the MDX content, we can use remarkPlugins and rehypePlugins. rehype-prism-plus is one of the "rehypePlugins".

So with putting rehypePrism in that rehypePlugins array, we can use rehypePrism just like it should be and without any additional configurations. The code is something like this:

// This is the UPDATED blog post layout component
import { serialize } from "next-mdx-remote/serialize";
import rehypePrism from "rehype-prism-plus";

const BlogPost = (props) => {
  // omitted
};

export const getStaticProps = async ({ params }) => {
  const content = {
    // omitted, not really like this
  };

  const mdxSource = await serialize(content, {
    mdxOptions: {
      remarkPlugins: [],
      rehypePlugins: [rehypePrism],
    },
  });

  return {
    // omitted
  };
};

Here is the whole code of this blog post page.

Screenshot: DOM with extra class
Screenshot: DOM with extra class

With this setup, if we inspect the code block with the Chrome dev tool, we can see that line 2 and line 16 have an extra class highlight-line (as seen in the screenshot above). Make sure the stylesheet for code block has highlight-inline style defined.

code[class*="language-"] .highlight-line {
  background-color: hsl(256deg 100% 96%);
  display: block;
}

I import this stylesheet in the _app.tsx file to make it use globally.