• Homeright arrow
  • Blogright arrow
  • A Powerful Combination of Markdown and MDX in Next.js for CMS
Feature

A Powerful Combination of Markdown and MDX in Next.js for CMS

Next.js continues to offer unmatched flexibility for developers, particularly when it comes to handling content. One of the best ways to manage rich content in Next.js is by using Markdown and MDX, two powerful formats that allow for easy content creation while leveraging the full potential of React components. In this blog, we’ll explore how to use Markdown and MDX effectively in your Next.js applications.

What is Markdown?

Markdown is a lightweight markup language designed for creating formatted text using a plain-text editor. It is popular for its simplicity and readability, and it's commonly used for writing documentation, blogs, and even comments. Markdown allows you to quickly format text without writing any complex HTML.

Basic Markdown Syntax:

  • Bold: text
  • Italic: text
  • Lists:
  • Unordered: - Item
  • Ordered: 1. Item
  • Links: [Link text](URL)
  • Code blocks:
```
code here
```

By default, Markdown is very limited in terms of interactivity. This is where MDX comes into play.

What is MDX?

MDX stands for Markdown + JSX. It’s an extension of Markdown that allows you to embed JSX directly within your Markdown content. This means you can seamlessly integrate interactive React components into your Markdown documents. This combination makes MDX incredibly powerful, enabling you to effortlessly create interactive and dynamic content.

For example:

import Alert from './Alert'
# Welcome to My Blog
Here is an important message:
<Alert>This is a React component inside MDX!</Alert>

Using Markdown and MDX in Next.js

Next.js can handle both local MDX content inside your application and distant MDX files downloaded dynamically from the server. The Next.js plugin converts markdown and React components to HTML and supports Server Components (the default in App Router). Let’s dive deep into it.

Prepare Your Next.js Application

Before setting up the GitHub Actions workflow, the first and foremost step is to create a Next.js App. Use the following command to create a next.js app.

npx create-next-app@latest app-name

As it is not an article on creating the next.js app, we will not discuss it in detail. If you want to read it in detail follow the link

Install dependencies

To render MDX with Next.js, you'll need to configure it with specific packages that allow the processing of markdown and MDX files. These packages enable Next.js to source data from local files and create pages with .md or .mdx extensions in your /pages or /app directory.

To get started, install the necessary packages:

npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx

This setup enables you to seamlessly render MDX content within your Next.js application, leveraging both Markdown and React components in the same files.

Configure next.config.mjs

Now, you have to configure the next.config.mjs file. Update the next.config.mjs file at your project's root to configure it to use MDX with the following codes:

import createMDX from '@next/mdx'

/** @type {import('next').NextConfig} */
const nextConfig = {
// Configure `pageExtensions` to include markdown and MDX files
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
// Optionally, add any other Next.js config below
}

const withMDX = createMDX({
// Add markdown plugins here, as desired
})

// Merge MDX config with Next.js config
export default withMDX(nextConfig)

This will enable your application to use .md and .mdx files as pages, routes, or imports.

Add an mdx-components.js file

Now you have to add the must-need file at the root of the project to define global MDX Components.  Let’s create the mdx-components.js. Now add the following codes:

export function useMDXComponents(components) {
return {
...components,
}
}


Note: mdx-components.js is required to use @next/mdx with App Router and will not work without it.

Rendering MDX

Rendering MDX files is the same as any .jsx or .js file. You can render MDX in Next.js either by utilizing its file-based routing system or importing MDX files into other pages.

Using file-based Routing

When using file-based routing, you can use MDX pages like any other page. So create a folder and name it  sample-mdx in the app folder. Now create a page.mdx file inside it. Now, add the following sample codes to the page.mdx file:

# Welcome to my MDX page!

This is some **bold** and _italics_ text.

This is a list in markdown:

- One
- Two
- Three

Checkout my React component:

Now if we navigate to sample-mdx route it will show the mdx page.

You can import any .jsx components in this MDX file also. Suppose we have a component named MyComponent. You can import and use it in the MDX file.

import  MyComponent  from '@/components/MyComponent'

# Welcome to my MDX page!

This is some **bold** and _italics_ text.

This is a list in markdown:

- One
- Two
- Three

Checkout my React component:

<MyComponent />

Using Import

You can import a MDX file also in the .jsx file. Create a new folder in the /app folder. Let’s name it import-mdx. Inside it add a page.jsx file. Also create a mdx file where you want in the project. In our case, create a /markdown.welcome.mdx file. Now you can use the file on the page.jsx file to display the content.

import Test from '@/markdown/test.mdx'

export default function Page() {
return <Test />
}

Styling a Markdown and MDX file

Markdown is automatically translated into native HTML elements. To customize the style of your Markdown content, you can create custom components that correspond to these generated HTML elements. You can customize them globally, locally or shared via layouts. Furthermore, you can use Tailwind CSS also.


Styles added in mdx-components.tsx will affect all MDX files in your application. Here is a sample example

import Image from "next/image";


// This file allows you to provide custom React components
// to be used in MDX files. You can import and use any
// React component you want, including inline styles,
// components from other libraries, and more.


export function useMDXComponents(components) {
return {
// Allows customizing built-in components, e.g. to add styling.
h1: ({children}) => <h1 style={{color: "red", fontSize: "48px"}}>{children}</h1>,
img: (props) => (
<Image
sizes="100vw"
style={{width: "100%", height: "auto"}}
alt="image"
{...props}
/>
),
...components,
};
}

You can apply custom styles and components to individual pages by passing them into imported MDX components. These local styles will merge with and can override any global styles or components.

import Test from "@/markdown/test.mdx";
function CustomH1({children}) {
return <h1 style={{color: "blue", fontSize: "100px"}}>{children}</h1>;
}
const overrideComponents = {
h1: CustomH1,
};
const page = () => {
return (
<>
<Test components={overrideComponents} />
</>
);
};

export default page;

You can also use a share method to add style. To share a common layout across multiple MDX pages, you can use the built-in layouts support with the App Router.

app/import-mdx/layout.js 
export default function MdxLayout({ children }) {
// Create any shared layout or styles here
return <div style={{ color: 'blue' }}>{children}</div>
}

In this example:

  • Shared Layout: The MdxLayout component acts as a wrapper that applies to all MDX pages within the directory. In this case, the layout wraps the content in a div with a blue text color.
  • {children}: This represents the content of the MDX page that will be passed into the layout. Each MDX page will be rendered inside the shared layout.
  • App Router: By placing the layout in the app/import-mdx/ directory, this layout will be applied to all pages under that path, ensuring consistency in styles or structure across these pages.

To make the styling simple, you can also use Tailwind CSS in your project. For example, Install Tailwind in your project if you have not installed it yet. Also, install tailwind typography using the following command:

npm install @tailwindcss/typography

Now, add the following code in the tailwind.config.js file plugins.

require("@tailwindcss/typography")    

Finally, update the  app/import-mdx/layout.js file.

export default function MdxLayout({children}) {
// Create any shared layout or styles here
return (
<div className="prose prose-headings:mt-8 prose-headings:font-semibold prose-headings:text-black prose-h1:text-5xl prose-h2:text-4xl prose-h3:text-3xl prose-h4:text-2xl prose-h5:text-xl prose-h6:text-lg dark:prose-headings:text-white mx-auto">
{children}
</div>
);

The @tailwindcss/typography plugin provides a set of prose classes that can be used to apply typographic styles to content blocks originating from Markdown.

Use Remote MDX

To dynamically fetch and display MDX content on your server from anywhere, you can use next-mdx-remote. This is particularly helpful if your MDX files or content are stored in a CMS, database, separate local folder, or other external sources. 

Create an app/remote-mdx/page.js file and add the following codes:

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} />
}

Now if we navigate to the remote-mdx route it will show the MDX page contents.

Note: Since MDX is compiled and executed as JavaScript on the server, always ensure that the source of your MDX content is trusted to prevent potential vulnerabilities like RCE.

Using Frontmatter

Frontmatter is a block of metadata placed at the top of a Markdown (or MDX) file. It is typically written in YAML or JSON format and is used to store additional information about the document, such as the title, date, author, tags, or other custom fields. @next/mdx by default does not support it. However, you can use some third-party libraries to add Frontmatter in an MDX file. Some of these are:


That’s all on Markdown and MDX in Next.js. To learn more about Markdown and MDX, you can visit the official https://nextjs.org/docs/app/building-your-application/configuring/mdx site.

Conclusion

Next.js  continues to push the boundaries of modern web development with powerful support for both Markdown and MDX. By harnessing the simplicity of Markdown and the interactivity of MDX, we can build engaging, content-rich applications without sacrificing performance.


Keep exploring and enhancing your Next.js projects! Please do not hesitate to contact StaticMania with any questions or feedback. Happy coding!

footer-particlefooter-particlefooter-particlefooter-particlefooter-particle
back-to-top