Using MDX with Next.js

Notes from configuring MDX on with-heart.xyz

Table of Contents

Initial installation

Adds support for .mdx files. Stores mdx-specific configuration in mdx.config.mjs.

ts
import withMdx from '@next/mdx'
export default withMdx({
extension: /\.mdx?$/,
})
ts
import withMdx from './mdx.config.mjs'
/** @type {import('next').NextConfig} */
const nextConfig = {
// default extensions + md + mdx
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
reactStrictMode: true,
swcMinify: true,
}
export default withMdx(nextConfig)

Export frontmatter as variables

We can export frontmatter as variables that can be accessed within mdx.

md
---
title: 'Some Title'
---
# {title}
⬇️
html
<h1>Some Title</h1>

We'll use remark-frontmatter and remark-mdx-frontmatter to accomplish this.

js
import withMdx from '@next/mdx'
import remarkFrontmatter from 'remark-frontmatter'
import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
export default withMdx({
extension: \/.mdx?$/,
options: {
remarkPlugins: [
[remarkFrontmatter],
[remarkMdxFrontmatter]
]
}
})

Code samples with VSCode syntax and TS compiler information

shiki-twoslash and remark-shiki-twoslash are made specifically for this purpose. Code blocks in ts twoslash fences work much like the TypeScript Playground editor.

js
import {nodeTypes} from '@mdx-js/mdx'
import withMdx from '@next/mdx'
import reypeRaw from 'rehype-raw'
import remarkShikiTwoslash from 'remark-shiki-twoslash'
/** @type {import('remark-shiki-twoslash').Options} */
const remarkShikiTwoslashOptions = {}
export default withMdx({
extension: /\.mdx?$/,
options: {
remarkPlugins: [[remarkShikiTwoslash.default, remarkShikiTwoslashOptions]],
rehypePlugins: [
// https://github.com/mdx-js/mdx/issues/1820#issuecomment-970430877
[rehypeRaw, {passThrough: nodeTypes}],
],
},
})