Using MDX in a Next.js Blog
MDX is a format that allows the use of custom components while also retaining the benefits of writing with markdown. Custom components can be written in any framework that uses JSX, including React and Vue. These components are imported at the top of an MDX file and allow the writer to completely customize their blog.
This guide will demonstrate how to use MDX in a Next.js app with custom React components.
Installation
To get started, first create a new Next app with the following command:
npx create-next-app mdx-blog
Next, add MDX to the app with this command:
npm install @next/mdx @mdx-js/loader @mdx-js/react
For the final step you will need to go to the next.config.json file in your directory. Paste the following code in that file:
const withMDX = require('@next/mdx')({
extension: /\.mdx?$/,
options: {
remarkPlugins: [],
rehypePlugins: []
}
})
module.exports = withMDX({
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx']
})
Layout
Layout components are often used in Next apps to avoid repeating code across your pages. These commonly include the navbar and footer for your site and return the children of your page between the two. This pattern is also useful when writing MDX files.
First, let's take a look at what a standard MDX file might look like:
import Layout from ../components/Layout
export const meta = {
title: 'Blog Title',
author: 'Blog Author'
}
# Blog Title
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
export default ({children}) => <Layout meta={meta}>{children}</Layout>
The Layout component is imported at the top of the file. This component will take everything written in the MDX and return the content for display.
Just below the Layout component is the article's metadata. This is a javascript object that will also be passed to the Layout component. Typically, the metadata will be used in conjuction with the Next.js Head component. Any data that you wish to pass from the MDX can be placed in this object.
At the bottom of the file, under the markdown, is the export for the page. The children passed to the Layout component are the markdown elements that will become HTML when rendered to the page. The meta object is passed as a prop of the Layout component.
Styling
The markdown elements in our MDX file will become HTML elements when rendered to the page. Normally, we would style elements with classes in the HTML or JSX. However, since the HTML is being generated elsewhere, styling is somewhat different for this case.
An easy solution to this is to use a container div in the Layout component and style the individual elements relative to that div. To do this, create a layout.module.css file in your styles folder. Here is an example layout component to illustrate how this works:
import styles from '../styles/layout.module.css'
import Navbar from './Navbar'
import Footer from './Footer'
export default function Layout({children}) {
return (
<>
<Navbar/>
<div className={styles.mdx}>
{children}
</div>
<Footer/>
</>
)
}
From here, you can style each element inside of the '.mdx' div. Because this uses CSS modules, you don't need to worry about your styling causing a conflict elsewhere on your site. This last block of code will demonstrate the styling in the CSS module:
.mdx > h1 {
font-size: 4rem;
}
.mdx > p {
font-size: 1rem;
margin-top: 1rem;
}