Skip to content

Latest commit

 

History

History
174 lines (136 loc) · 5.02 KB

syntax-highlighting.mdx

File metadata and controls

174 lines (136 loc) · 5.02 KB

import {Note} from '../_component/note.jsx'

export const info = { author: [ {github: 'wooorm', name: 'Titus Wormer', twitter: 'wooorm'} ], modified: new Date('2023-10-23'), published: new Date('2021-10-06') } export const navSortSelf = 4

Syntax highlighting

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.)

Syntax highlighting at compile time

Use either rehype-highlight (highlight.js) or @mapbox/rehype-prism (Prism) by doing something like this:

import {compile} from '@mdx-js/mdx'
import rehypeHighlight from 'rehype-highlight'

const code = `~~~js
console.log(1)
~~~`

console.log(
  String(await compile(code, {rehypePlugins: [rehypeHighlight]}))
)
Expand equivalent JSX
<>
  <pre>
    <code className="hljs language-js">
      <span className="hljs-variable language_">console</span>.
      <span className="hljs-title function_">log</span>(
      <span className="hljs-number">1</span>)
    </code>
  </pre>
</>
**Important**: If you chose `rehype-highlight`, then you should also use a highlight.js theme somewhere on the page. For example, to get GitHub Dark from cdnjs:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css">

{/* to do: once in a while, get the latest: https://github.com/wooorm/lowlight#css */}

If you chose @mapbox/rehype-prism, include something like this instead to get Prism Dark:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.27.0/themes/prism-dark.min.css">

{/* to do: once in a while, get the latest: https://github.com/wooorm/refractor#css */}

Syntax highlighting at run time

Use for example react-syntax-highlighter, by doing something like this:

import SyntaxHighlighter from 'react-syntax-highlighter'
import Post from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

<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>
</>

Syntax highlighting with the meta field

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 remark plugin remark-mdx-code-meta 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 remark plugins, can be passed as remarkPlugins in ProcessorOptions. More info on plugins is available in § Extending MDX