import {Note} from '../_component/note.jsx'
export const info = { author: [ {github: 'wooorm', name: 'Titus Wormer'} ], modified: new Date('2025-01-27'), published: new Date('2021-10-06') } export const navSortSelf = 4
This guide explores how to apply syntax highlighting to code blocks. {/* more */} MDX supports standard markdown syntax (CommonMark). It does not apply syntax highlighting to code blocks by default.
There are two ways to accomplish syntax highlighting: at compile time or at runtime. Doing it at compile time means the effort is spent upfront so that readers will have a fast experience as no extra code is sent to them (syntax highlighting needs a lot of code to work). Doing it at runtime gives more flexibility by moving the work to the client. This can result in a slow experience for readers though. It also depends on what framework you use (as in it’s specific to React, Preact, Vue, etc.)
Use for example rehype-starry-night
(starry-night
),
rehype-highlight
(lowlight
, highlight.js
),
or @mapbox/rehype-prism
(refractor
, prism
)
by doing something like this:
/// <reference types="node" />
// ---cut---
import {compile} from '@mdx-js/mdx'
import rehypeStarryNight from 'rehype-starry-night'
const code = `~~~js
console.log(1)
~~~`
console.log(
String(await compile(code, {rehypePlugins: [rehypeStarryNight]}))
)
Expand equivalent JSX
<>
<pre>
<code className="language-js">
<span className="pl-en">console</span>.<span className="pl-c1">log</span>(<span className="pl-c1">1</span>)
</code>
</pre>
</>
Use for example
react-syntax-highlighter
,
by doing something like this:
{/* Note: react-syntax-highlighter
doesn’t seem actively maintained so no twoslash to check this example. */}
import SyntaxHighlighter from 'react-syntax-highlighter'
import Post from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(<Post components={{code}} />)
function code({className, ...properties}) {
const match = /language-(\w+)/.exec(className || '')
return match
? <SyntaxHighlighter language={match[1]} PreTag="div" {...properties} />
: <code className={className} {...properties} />
}
Expand equivalent JSX
<>
<pre>
<div
className="language-js"
style={{
background: '#F0F0F0',
color: '#444',
display: 'block',
overflowX: 'auto',
padding: '0.5em'
}}
>
<code style={{whiteSpace: 'pre'}}>
<span>console.</span>
<span style={{color: '#397300'}}>log</span>
<span>(</span>
<span style={{color: '#880000'}}>1</span>
<span>)</span>
</code>
</div>
</pre>
</>
Markdown supports a meta string for code:
```js filename="index.js"
console.log(1)
```
The meta
part is everything after the language (in this case, js
).
This is a hidden part of markdown: it’s normally ignored.
But as the above example shows, it’s a useful place to put some extra fields.
@mdx-js/mdx
doesn’t know whether you’re handling code as a component or what
the format of that meta string is, so it defaults to how markdown handles it:
meta
is ignored.
But what if you want to access meta
at runtime?
That’s exactly what the rehype plugin
rehype-mdx-code-props
does.
It lets you type JSX attributes in the meta
part which you can access by
with a component for pre
.
That plugin, like all rehype plugins, can be passed as
rehypePlugins
in ProcessorOptions
.
More info on plugins is available in § Extending MDX