MDX Pretty Code
A Remark plugin to make the code in your MDX docs simply beautiful. Powered by
Shiki.
- ✅ Perfect VS Code highlighting (use any theme)
- ✅ Line and word highlighting
- ✅ Context-adjustable inline code highlighting
Installation
ESM contexts:
npm install @atomiks/mdx-pretty-code shiki unist-util-visit
CJS contexts:
npm install @atomiks/mdx-pretty-code shiki unist-util-visit@2
Usage
import {createRemarkPlugin} from '@atomiks/mdx-pretty-code';
import fs from 'fs';
const prettyCode = createRemarkPlugin({
shikiOptions: {
theme: JSON.parse(
fs.readFileSync(require.resolve('./themes/my-theme.json'), 'utf-8')
),
},
onVisitLine(node) {
Object.assign(node.style, {
margin: '0 -1.5rem',
padding: '0 1.5rem',
});
},
onVisitHighlightedLine(node) {
Object.assign(node.style, {
backgroundColor: 'rgba(0,0,0,0.1)',
});
},
onVisitHighlightedWord(node) {
Object.assign(node.style, {
backgroundColor: 'rgba(0,0,0,0.5)',
padding: '0.25rem',
borderRadius: '0.25rem',
});
},
});
Then pass the plugin to your MDX remarkPlugins
option. For example, in
next.config.js
using MDX v2:
module.exports = {
experimental: {esmExternals: true},
webpack(config, options) {
config.module.rules.push({
test: /\.mdx?$/,
use: [
options.defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: {
remarkPlugins: [prettyCode],
},
},
],
});
return config;
},
};
API
Code blocks are configured via the meta string after the top codeblock fence.
Line highlighting
Highlight lines 1, 2 through 4, and 6.
```js {1,2-4,6}
Word highlighting
Highlight the literal word carrot
. Regex is not currently supported.
```js /carrot/
Limit word highlighting to specific instances
If you want to limit which words get highlighted, this is possible. For
instance:
```js /carrot/1-2,4
The numeric range must be directly after the /
.
This will only highlight the first, second, and fourth instances of carrot
,
but not the third, or fifth+.
Inline highlighting
Append {:lang}
(e.g. {:js}
) at the end of the inline code to highlight it
like it's a regular code block.
This is `inline(){:js}` code which will be colored like a regular code block.
In your MDXProvider
's components
prop, modify span
like so:
const mdxComponents = {
span(props) {
if (props['data-mdx-pretty-code'] != null) {
return (
<code style={{color: props['data-color']}}>
{props.children.props.children}
</code>
);
}
return <span {...props} />;
},
};
Context-specific highlighting
Shiki will color plain variables as plain text since the highlighting has no
context. But if you're referring to a variable which was colored a different way
by Shiki in a code block above or below the inline code, it won't be semantic.
You can instruct MDX Pretty Code to color a word by supplying a token whose
color is specified in the VS Code theme.
It must start with a .
to indicate it's a token, not a language.
The function name is `hello{:.entity.name.function}`.
You can create a tokensMap
to shorten this throughout your docs:
createRemarkPlugin({
tokensMap: {
function: 'entity.name.function',
},
});
Now you can just do:
The function name is `hello{:.function}`.
Note: for the token feature to work, you must have supplied a JSON object to
shikiOptions.theme
, not a default Shiki theme string.
Sanitizing
All HTML is sanitized via
sanitize-html
. To configure the
sanitizing options, pass sanitizeOptions
, which is 1:1 with its API.
License
MIT