Rehype Pretty Code

July 6, 2023

Rehype Pretty Code is a Rehype plugin powered by the Shiki syntax highlighter that provides beautiful code blocks for Markdown or MDX. It's fast since it avoids runtime syntax highlighting by executing at build-time, and works with new features like React Server Components.

Perfect syntax highlighting

Leverage the accuracy of VS Code's syntax highlighting engine and the popularity of its themes ecosystem — use any VS Code theme you want!

js
import Document, { Html, Head, Main, NextScript } from "next/document"; // 🔥 Super granular and accurate highlighting export default class MyDocument extends Document { static async getInitialProps(ctx) { const initialProps = await Document.getInitialProps(ctx); return { ...initialProps }; } render() { return ( <Html> <Head /> <body className='bg-zinc-800 text-zinc-200'> <Main /> <NextScript /> </body> </Html> ); } }

Line numbers are supported

js
import { useFloating } from "@floating-ui/react"; function MyComponent() { const { refs, floatingStyles } = useFloating(); return ( <> <div ref={refs.setReference} /> <div ref={refs.setFloating} style={floatingStyles} /> </> ); }

Word highlighting

js
import { useFloating } from "@floating-ui/react"; function MyComponent() { const { refs, floatingStyles } = useFloating(); return ( <> <div ref={refs.setReference} /> <div ref={refs.setFloating} style={floatingStyles} /> </> ); }

Inline code highlighting

The result of [1, 2, 3].join('-') is '1-2-3'.

Context-aware inline code

For instance, if you had the following code block:

js
function getStringLength(str) { return str.length; }

When we refer to getStringLength as a plain variable, we can color it as a function. Same with function, or str vs. str, etc. This allows you to semantically tie inline code with the nearest code block it's referring to.

ANSI highlighting

ansi
vite v2.8.6 dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in 125ms. 8:38:02 PM [vite] hmr update /src/App.jsx

Inline ANSI: > Local: http://localhost:3000/

Installation

Install via your terminal:

shell
npm install rehype-pretty-code shiki

Usage

js
import { unified } from "unified"; import remarkParse from "remark-parse"; import remarkGfm from "remark-gfm"; import remarkRehype from "remark-rehype"; import rehypeStringify from "rehype-stringify"; import rehypePrettyCode from "rehype-pretty-code"; async function main() { const file = await unified() .use(remarkParse) .use(remarkGfm) .use(remarkRehype) .use(rehypePrettyCode, { // See Options section below. }) .use(rehypeStringify) .process("`const numbers = [1, 2, 3]{:js}`"); } main();

MDX

The following example shows how to use this package with Next.js.

js
const rehypePrettyCode = require("rehype-pretty-code"); const fs = require("fs"); /** @type {import('rehype-pretty-code').Options} */ const options = { // See Options section below. }; const withMDX = require("@next/mdx")({ extension: /\.mdx?$/, options: { remarkPlugins: [], rehypePlugins: [[rehypePrettyCode, options]], }, });

Make sure you have disabled the mdxRs option for Next.js 13 / app dir, as it currently does not support Rehype plugins.

Options

To customize the theme and highlighting, options can be specified.

Code block styles

Code blocks are unstyled to give you full control. Code blocks however assume a grid style, so ensure the following style is present:

css
pre > code { display: grid; }

This allows line highlighting to span the entire width of a horizontally-scrollable code block.

You can disable this setting if necessary:

js
const options = { grid: false, };

Theme

The default theme is github-dark-dimmed. Shiki has a bunch of pre-packaged themes, which can be specified as a plain string:

js
const options = { theme: "one-dark-pro", };

But you can use your own theme as well by passing the theme JSON:

js
// ESM const options = { theme: JSON.parse( readFileSync(new URL("./themes/theme.json", import.meta.url)) ), };
js
// CJS const options = { theme: JSON.parse( fs.readFileSync(require.resolve("./themes/dark.json"), "utf-8") ), };
Your name here© 2023