Skip to content
MDX logoMDX v1.3.2
GitHub logo

Syntax highlighting

There are two primary approaches for adding syntax highlighting to MDX:

  • composition via the MDXProvider
  • remark plugin

It’s typically preferred to take the compositional approach, but both will be documented here.

Composition

The MDXProvider provides a way to map components to be rendered for a given Markdown element. So, this allows you to choose a specific component for the code block. To get started you can wrap your app in the MDXProvider and add in a component to ensure it’s being picked up:

Using the MDXProvider

// src/App.js
import React from 'react'
import {MDXProvider} from '@mdx-js/react'
const components = {
pre: props => <div {...props} />,
code: props => <pre style={{ color: 'tomato' }} {...props} />
}
export default props => (
<MDXProvider components={components}>
<main {...props}>
</main>
</MDXProvider>
)

When you render your app you should now see the color become tomato for any code block found in your MDX files.

prism-react-renderer

Now that you have a custom component being rendered for code blocks you can choose any React component library to handle the syntax highlighting. A solid library to choose is prism-react-renderer.

You can install it with:

yarn add prism-react-renderer

Build a CodeBlock component

You can essentially cut and paste the entire example into a new component file. The only big difference is the MDX will pass in the code string as children so you will need to destructure that prop and pass it to Highlight as the code prop.

// src/CodeBlock.js
import React from 'react'
import Highlight, {defaultProps} from 'prism-react-renderer'
export default ({children}) => {
return (
<Highlight {...defaultProps} code={children} language='javascript'>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={className} style={{...style, padding: '20px'}}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({line, key: i})}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
}

Now you should see syntax highlighting in your MDX files. However, right now javascript is hardcoded as the language. You will need to take the language from the code fence and pass it to Highlight directly. MDX will pass the language as className so you can pull out the language with:

const language = className.replace(/language-/, '')

All together

import React from 'react'
import Highlight, {defaultProps} from 'prism-react-renderer'
export default ({children, className}) => {
const language = className.replace(/language-/, '')
return (
<Highlight {...defaultProps} code={children} language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={className} style={{...style, padding: '20px'}}>
{tokens.map((line, i) => (
<div key={i} {...getLineProps({line, key: i})}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
))}
</pre>
)}
</Highlight>
)
}

See the example

Remark plugin

In addition to composition you can use any plugin from the remark ecosystem. One solid library for syntax highlighting is @mapbox/rehype-prism.

// webpack.config.js
const rehypePrism = require('@mapbox/rehype-prism')
module.exports = {
module: {
// ...
rules: [
// ...
{
test: /.mdx?$/,
use: [
'babel-loader',
{
resolve: '@mdx-js/loader',
options: {
rehypePlugins: [rehypePrism]
}
}
]
}
]
}
}

Read more about plugins

Edit this page on GitHub
Previous:
Guides
Next:
Live code editor