Syntax Highlighting
Nextra uses Shiki to do syntax highlighting at build time. It’s very reliable and performant. For example, adding this in your Markdown file:
```js
console.log('hello, world')
```
Result in this:
console.log('hello, world')
Features
Inlined Code
Inlined syntax highlighting like let x = 1
is also supported via the {:}
syntax:
Inlined syntax highlighting is also supported: let x = 1
Filenames and Titles
You can add a filename or a title to your code blocks by adding a filename
attribute:
Renders:
console.log('hello, world')
Highlighting Lines
You can highlight specific lines of code by adding a {}
attribute to the code block:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
You can highlight only a part of the occurrences of that substring by adding a number it: /str/1
, or multiple: /str/1-3
, /str/1,3
.
Line Numbers
You can add line numbers to your code blocks by adding a showLineNumbers
attribute:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
Supported Languages
Check this list for all supported languages.
Customize the Theme
Nextra uses CSS variables to define the colors for tokens. You can inject a global CSS to customize them under light/dark themes. For example this is the default tokens and you can override any of these:
:root {
--shiki-color-text: #414141;
--shiki-color-background: transparent;
--shiki-token-constant: #1976d2;
--shiki-token-string: #22863a;
--shiki-token-comment: #aaa;
--shiki-token-keyword: #d32f2f;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #6f42c1;
--shiki-token-string-expression: #22863a;
--shiki-token-punctuation: #212121;
--shiki-token-link: #22863a;
}
.dark {
--shiki-color-text: #d1d1d1;
--shiki-token-constant: #79b8ff;
--shiki-token-string: #ffab70;
--shiki-token-comment: #6b737c;
--shiki-token-keyword: #f97583;
--shiki-token-parameter: #ff9800;
--shiki-token-function: #b392f0;
--shiki-token-string-expression: #4bb74a;
--shiki-token-punctuation: #bbb;
--shiki-token-link: #ffab70;
}
With Dynamic Content
Since syntax highlighting is done at build time, you can’t use dynamic content in your code blocks. However, since MDX is very powerful there is a workaround via client JS. For example:
function hello () {
const x = 2 + 3
console.log(1)
}
This workaround has a limitation that updated content won’t be re-highlighted. For example if we update the number to 1 + 1
, it will be incorrectly highlighted.
Disable Syntax Highlighting
You can opt out of syntax highlighting for using one of your own. You can disable syntax highlighting globally by setting codeHighlight: false
in your Nextra configuration (next.config.js
file).
Key | Type | Description | Example |
---|---|---|---|
codeHighlight | boolean | Enable or disable syntax highlighting. | codeHighlight: true |
Custom Grammar
Shiki accepts a VSCode TextMate Grammar for syntax highlighting with custom language grammars.
You can provide these grammars by overriding the getHighlighter
function in mdxOptions.rehypePrettyCodeOptions
option in your Nextra config inside next.config.js
:
import { BUNDLED_LANGUAGES } from 'shiki'
nextra({
// ... other options
mdxOptions: {
rehypePrettyCodeOptions: {
getHighlighter: (options) =>
getHighlighter({
...options,
langs: [
...BUNDLED_LANGUAGES,
// custom grammar options, see the Shiki documentation for how to provide these options
{
id: 'my-lang',
scopeName: 'source.my-lang',
aliases: ['mylang'], // Along with id, aliases will be included in the allowed names you can use when writing markdown.
path: '@/public/syntax/grammar.tmLanguage.json',
},
],
}),
},
},
})
Custom Themes
Within mdxOptions.rehypePrettyCodeOptions
you may also provide custom themes instead of relying on CSS Variables:
nextra({
// ... other options
mdxOptions: {
rehypePrettyCodeOptions: {
// VSCode theme or built-in Shiki theme, see Shiki documentation for more information
theme: JSON.parse(
readFileSync('./public/syntax/arctis_light.json', 'utf8')
)
}
}
})