Syntax Highlighting
Nextra uses Shiki (opens in a new tab) 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')
```Results in:
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{:jsx}` via:Highlighting Lines
You can highlight specific lines of code by adding a {} attribute to the code
block:
```js {1,4-5}
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```Result:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}Highlighting Substrings
You can highlight specific substrings of code by adding a // attribute to the
code block:
```js /useState/
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```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.
Copy Button
By adding a copy attribute, a copy button will be added to the code block when
the user hovers over it:
```js copy
console.log('hello, world')
```Renders:
console.log('hello, world')You can enable this feature globally by setting defaultShowCopyCode: true in
your Nextra configuration (next.config.js file). Once it's enabled globally,
you can disable it via the copy=false attribute.
Line Numbers
You can add line numbers to your code blocks by adding a showLineNumbers
attribute:
```js showLineNumbers
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
```Renders:
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}Filenames and Titles
You can add a filename or a title to your code blocks by adding a filename
attribute:
```js filename="example.js"
console.log('hello, world')
```Renders:
console.log('hello, world')ANSI Highlighting
You can highlight ANSI escape codes:
```ansi
[0m [0;32m✓[0m [0;2msrc/[0mindex[0;2m.test.ts (1)[0m
[0;2m Test Files [0m [0;1;32m1 passed[0;98m (1)[0m
[0;2m Tests [0m [0;1;32m1 passed[0;98m (1)[0m
[0;2m Start at [0m 23:32:41
[0;2m Duration [0m 11ms
[42;1;39;0m PASS [0;32m Waiting for file changes...[0m
[0;2mpress [0;1mh[0;2m to show help, press [0;1mq[0;2m to quit
```Renders:
✓ src/index.test.ts (1)
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 23:32:41
Duration 11ms
PASS Waiting for file changes...
press h to show help, press q to quitSupported Languages
Check this list (opens in a new tab) for all supported languages.
Customize the Theme
Nextra uses CSS variables to define the colors for tokens. You can inject a global CSS (opens in a new tab) 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.
Check out the code (opens in a new tab) to see how it works.
Custom Grammar
Shiki accepts a VSCode TextMate Grammar (opens in a new tab) 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')
)
}
}
})Multiple Themes
Nextra currently doesn't support specifying multiple themes. Because Shiki
renders multiple code blocks for every theme and tags them with an attribute
data-theme, e.g. data-theme="dark".
However, in the future, multiple themes will be supported. You can track the progress in shikiji (newly fork of Shiki) https://github.com/antfu/shikiji#multiple-themes (opens in a new tab) that already supports multiple themes without rendering multiple code blocks.