You've reached the end. Thanks for reading!
Let me introduce you to a Rehype plugin called rehype-pretty and a syntax highlighter called shiki. These are the two tools we will be using to add beautiful syntax highlighting to our MDX files.
First we need to install the required packages into our project.
npm install rehype-pretty-code shikiUsing the next-mdx-remote package.
import { MDXRemote } from "next-mdx-remote/rsc";
import rehypePrettyCode from "rehype-pretty-code";
/** @type {import('rehype-pretty-code').Options} */
const options = {};
export function Content({ source }: { source:
Using the @next/mdx package.
The code below can be found at rehype-pretty.pages.dev/#mdx.
import rehypePrettyCode from "rehype-pretty-code";
import nextMDX from "@next/mdx";
/** @type {import('rehype-pretty-code').Options} */
const options = {};
const withMDX = nextMDX({
extension: /\.mdx
Using the unified package.
The code below can be found at rehype-pretty.pages.dev/#usage.
import rehypePrettyCode from "rehype-pretty-code";
import rehypeStringify from "rehype-stringify";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import { unified } from "unified";
async function main
If you're using another way of rendering your Markdown files, you just need to add the plugin to the array of rehype plugins, this can be found in the documentation of the package you're using.
Now that we have the plugin installed and configured, we can start declaring our code blocks. You can declare a code block using 3 backticks (`), like this:
```js
function add(a, b) {
return a + b;
}
```The code above will look something like this when rendered:
function add(a, b) {
return a + b;
}By default this plugin is unstyled, meaning the styles need to be provided by us.
The default theme is github-dark-dimmed, though shiki provides some themes out of the box, which can be defined in the options the following way:
const options = {
theme: "one-dark-pro",
};The following code will set the --shiki-dark and --shiki-light variables to the respective themes, which will be used to style the code block.
const options = {
theme: {
dark: "github-dark",
light: "github-light",
},
};code[data-theme*=" "],
code[data-theme*=" "] span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}
html.dark code[data-theme*=
code[data-theme*=" "],
code[data-theme*=" "] span {
color: var(--shiki-light);
background-color: var(--shiki-light-bg);
}
@media (prefers-color-scheme: dark) {
code[data-theme
To achieve a similar look to the one you see on my blog, you can use the following CSS:
pre {
overflow-x: auto !important;
}
pre [data-line] {
padding-left: 1rem;
padding-right: 1rem;
}This adds a scrollbar to the code block when it overflows and adds padding to each line.
Now onto configuring the <pre> component in the markdown-components.tsx file.
import { MDXComponents } from "mdx/types";
import { reactToText } from "react-to-text";
import { CopyButton } from "path/to/copy-button";
export const mdxComponents: MDXComponents = {
...
WarningIf you're using the
title=""attribute for your code block, rehype-pretty will create a new<figcaption>component. This will cause 2<figcaption>components to be rendered. To avoid this, please move the aforementioned component you see in the example above, tofigcaption: (props) => ()inside ofmarkdown-components.tsx. Though now, you need to make some style adjustments to the component, along with getting the content of the code block for the<CopyButton.
Feel free to style the components in any way you want. In this example I am using TailwindCSS.
This code uses the react-to-text package to convert the children of the <pre> component to a string and then passes that string to the <CopyButton> component which you need to create yourself.
How it works is actually pretty simple. You just need to provide the text prop to the <CopyButton> component and listen to an onClick event to copy the text to the clipboard.
data-language is the language you've specified in the code block of your MDX
file.
The reason why a react fragment (<></>) is used, is because each code block gets wrapped in a <figure> component. Thus the resulting code will look something like this:
<figure>
<figcaption></figcaption>
<pre>
<code></code>
</pre>
</figure>CSS counters can be used to add line numbers to your code blocks.
pre [data-line] {
padding-left: 1rem;
padding-right: 1rem;
}
code[data-line-numbers] {
counter-reset: line;
}
code[data-line-numbers
You can then use showLineNumbers to add line numbers to your code blocks.
```js showLineNumbers
function add(a, b) {
return a + b;
}
```function add(a, b) {
return a + b;
}You can highlight lines using {2,7}, this will highlight lines 2 and 7. A range can also be specified using {2-7}, this will highlight lines 2 through 7.
```js {2,7}
function add(a, b) {
return a + b;
}
const sum = add(1, 2);
console.log(sum);
```function add(a, b) {
return a + b;
}
const sum = add(1, 2);
console.log(sum);To highlight the word add you can use /add/.
```js /add/
function add(a, b) {
return a + b;
}
const sum = add(1, 2);
console.log(sum);
```function add(a, b) {
return a + b;
}
const sum = add(1, 2);
console.log(sum);Now you can add syntax highlighting to your MDX files in Next.js. If you have any questions or feedback, please don't hesitate to reach out, I'm always happy to help and improve this guide. Almost everything in this guide can be found in the official documentation of rehype-pretty, make sure to check it out.