Back to posts
Next.js + MDX

Next.js + MDX

Sami Paananen / Sep 27, 2024

MDX?

MDX is a way to write Markdown syntax with JSX components. It simplifies and streamlines the process of producing blog content or other materials for an application, allowing custom components to be used within Markdown syntax.

MDX is compiled into JavaScript when integrated into the browser or application, which means it generates JavaScript components used to display content.

  • MDX
// content.mdx
# welcome

first paragraph

<Button />

second paragraph

## subtitle
  • JSX
// content.jsx
<h1>welcome</h1>
<p>first paragraph</p>
<button onClick={()=> ...doSomething}>action</button>
<p>second paragraph</p>
<h2>subtitle</h2>

In the example above, the same content is created for a blog site, one using MDX and the other using JSX.

Which do you think would be a more natural approach?

MDX Remote

With the MDX Remote package, data can be fetched from any location such as a database, object, or local file and converted into components that the browser can process.

npm i next-mdx-remote
  • Reading and returning MDX data in the correct format:
import { MDXRemote } from 'next-mdx-remote/rsc'

export default async function RemoteMdxPage() {
  // MDX text - can be from a local file, database, CMS, fetch, anywhere...
  const res = await fetch('https://...')
  const markdown = await res.text()
  return <MDXRemote source={markdown} />
}

Metadata

Metadata in MDX is referred to as front-matter, which contains information like title, description, publication date, etc. Metadata in MDX is defined at the top of the file between three dashes:

---
title: Next.js  MDX
description: Learn to create dynamic blogs quickly and easily with Next.js and MDX.
image: '/images/blog/nextjs-and-mdx/nextjsmdx.webp'
author: 'Sami Paananen'
publishedAt: '2024-09-27'
---

Metadata can be extracted directly from MDX using the gray-matter package. With this information, we can already create a preview page of our content.

npm i gray-matter
import matter from 'gray-matter'

function getMetadata() {
    const file = ...getMDXContent

    return matter(file)
}

Styling Content

In the first example, .mdx only produced raw HTML elements without any classes to add styling. How can we, for example, define that all text should be red (though I’m not sure why anyone would want to do that)?

In this case, we use the Tailwind typography package, which allows us to style all HTML elements and their sub-elements. We simply apply the prose class to the parent element. It is also possible to customize the entire prose class to fit our needs.

npm i @tailwindcss/typography
// globals.css
.prose * {
    @apply text-red-600
  }
<main className='prose mt-16 dark:prose-invert'>
    <MDXContent source={content} />
</main>

Customizing Components and Integration

We can also control how an element is rendered when MDX encounters it during integration. We create a mapping of custom components:

import Counter from '@/components/counter'

function MdxContentPage() {
    //TODO: Get mdxSource

    const overrideComponents = {
        h1: ({ children }) => <h1 style={{ color: 'blue', fontSize: '100px' }}>{children}</h1>,
        h2: ({ children }) => <h2 style={{ color: 'red', fontSize: '200px' }}>{children}</h2>
        Counter: Counter
    }

    return <MDXRemote source={mdxSource} components={overrideComponents}
}

Here we see the true strength of MDX and JSX integration. It brings together the clarity of Markdown and the complexity of JSX, allowing us to use the best of both where needed. The Counter component can contain any interactivity that JSX allows, and it is available in MDX.

Conclusion

Next.js’s feature of caching similar data fetches combined with MDX’s straightforward content creation method makes it a highly viable combination for creating high-performance applications with consistent and interactive content.

Even this blog proves the previous statement.

Links

If you'd like more information on how to quickly and easily set up your own blog with local files, feel free to reach out.

Cheers,
Sami Paananen
Software developer

Comments