Jses.ioby Shaojiang

Next.js 13: Interpreting and Displaying Markdown Text

Shaojiang

Date:

Next.js 13: Interpreting and Displaying Markdown Text

1. Introduction

Next.js, a popular React framework for building server-side rendered (SSR) and static websites, introduces @next/mdx in its latest version, Next.js 13, for interpreting and displaying Markdown text. Markdown is a lightweight markup language known for its simplicity and readability. In this article, we will explore how to integrate and render Markdown content using the @next/mdx library.

2. Why Markdown?

Markdown is widely used by content creators, developers, and writers due to its intuitive syntax and ease of use. By combining plain text with simple markup, Markdown enables the creation of structured documentation, blog posts, and other textual content without the need for complex formatting.

The input:

I **love** using [Next.js](https://nextjs.org/)

After interpreting, the output is:

<p>I <strong>love</strong> using <a href="https://nextjs.org/">Next.js</a></p>

MDX  is a superset of markdown that lets you write JSX  directly in your markdown files. It is a powerful way to add dynamic interactivity and embed React components within your content.

3. Markdown Support with @next/mdx

Next.js 13 introduces @next/mdx, a comprehensive solution for working with Markdown in a Next.js project. It seamlessly integrates Markdown rendering into your application using a combination of Next.js's serverless functions and the MDX (Markdown + JSX) syntax.

4. Install the required packages

To begin, ensure that you have Next.js 13 installed. Then, follow these steps to get started with @next/mdx.

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

5. Create mdx-components.tsx

According to Next.js official doc: MDX and MDX support width appDir enabled:

Good to knowmdx-components.tsx is required to use MDX with App Router and will not work without it.

However, it is still working properly without mdx-components.tsx in the Demo Repo. Probably there are minor releases that have removed the dependency of it.

6. Modify next.config.js

To use MDX, need to update the Next.js config file next.config.js:

1const withMDX = require('@next/mdx')()
2
3/** @type {import('next').NextConfig} */
4const nextConfig = {
5 // Configure `pageExtensions`` to include MDX files
6 pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
7 // Optionally, add any other Next.js config below
8}
9
10module.exports = withMDX(nextConfig)

7. Render Markdown/MDX

Now we can render component with Markdown/MDX syntax. Add a file src/app/privacy/privacy.mdx:

1# Privacy Policy
2
3Jianxi Limited operates the [Jses.io](https://jses.io) website, which provides a _community_ for **developers** to play with new ideas and techs.

Add src/app/privacy/page.tsx to render the MDX:

1'use client';
2
3import React from 'react';
4
5import Privacy from './privacy.mdx';
6
7export default function PrivacyPage() {
8 return (
9 <div className='prose'>
10 <Privacy />
11 </div>
12 );
13}
14

Run yarn dev and visit http://localhost:3000/privacy, you should be able to see the page like:

Inspect the page and you will find the rendered html to be like:

1<div class='prose'>
2 <h1>Privacy Policy</h1>
3 <p>
4 Jianxi Limited operates the <a href='https://jses.io'>Jses.io</a> website, which provides
5 a <em>community</em> for <strong>developers</strong> to play with new ideas and techs.
6 </p>
7</div>

8. Component in MDX

MDX allows us to render a React component inside. Create a testing component src/app/privacy/button.tsx:

1import React from 'react';
2
3export default function Button({ children }: { children: React.ReactNode }) {
4 return (
5 <button className='m-4 px-4 py-2 transition-all outline-0 rounded bg-purple-900 text-white shadow hover:relative hover:bottom-1'>
6 {children}
7 </button>
8 )
9}

Then we can import and render it in the .mdx file, the file will be:

1import Button from './button';
2
3# Privacy Policy
4
5<Button>Report</Button>
6
7Jianxi Limited operates the [Jses.io](https://jses.io) website, which provides a _community_ for **developers** to play with new ideas and techs.

The page now looks:

9. Remark plugins

We can now optionally add plugins to make the rendering more convenient. For example, remark-gfm supports GFM (autolink literals, footnotes, strikethrough, tables, tasklists). Since the remark and rehype ecosystem is ESM only, you'll need to use next.config.mjs as the configuration file. Please remember to change the file suffix from .js to .mjs. Otherwise, the app cannot be started:

Content of next.config.mjs becomes:

1import remarkGfm from 'remark-gfm'
2import createMDX from '@next/mdx'
3
4/** @type {import('next').NextConfig} */
5const nextConfig = {
6 // Configure `pageExtensions`` to include MDX files
7 pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
8 // Optionally, add any other Next.js config below
9}
10
11const withMDX = createMDX({
12 // Add markdown plugins here, as desired
13 options: {
14 remarkPlugins: [remarkGfm],
15 rehypePlugins: [],
16 },
17})
18
19// Merge MDX config with Next.js config
20export default withMDX(nextConfig)

With the plugin enabled, the renderer supports features like hyperlinks automatically. For example, https://jses.io will be rendered as <a href="https://jses.io">https://jses.io</a>.

10. Conclusion

We have now enabled the Markdown/MDX rendering on in a Next.js app. Please checkout the Demo Repo and play with it.