Markdown, Please
Published Feb 21st, 2025
I knew from the beginning making this website that I'd want the ability to write my articles using markdown, but in an effort to get something up and running quickly, I just did my first article in plain old HTML.
I thought I might need to write a preprocessor myself to convert markdown files to the correct format, but it turns Next.js already has a good solution for this!
This article from the Next.js team does a great job at explaining how to setup your Next.js application to work with markdown:
Configuring: MDX | Next.js
Learn how to configure MDX to write JSX in your markdown files.
Implementation for scotthaley.dev
First thing was to add the withMDX
plugin to Next.js.
/next.config.ts
1import type { NextConfig } from "next";
2import createMDX from "@next/mdx";
3
4const nextConfig: NextConfig = {
5 /* config options here */
6 pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
7};
8
9const withMDX = createMDX({});
10
11export default withMDX(nextConfig);
In our next.config.ts
file, we create an instance of the MDX plugin
and wrap our nextConfig
with withMDX()
.
The next thing we need to do is create a mdx-components.tsx
file in our project root directory.
The MDX plugin will not work without this file.
/mdx-components.tsx
1import type { MDXComponents } from "mdx/types";
2import Image, { ImageProps } from "next/image";
3
4export function useMDXComponents(components: MDXComponents): MDXComponents {
5 return {
6 h1: ({ children }) => (
7 <div className="mb-10 border-b-theme-2 border-b-2 w-full px-6">
8 <h1>{children}</h1>
9 </div>
10 ),
11 h2: ({ children }) => <h2 className="px-6">{children}</h2>,
12 h3: ({ children }) => <h3 className="px-6">{children}</h3>,
13 h4: ({ children }) => <h4 className="px-6">{children}</h4>,
14 h5: ({ children }) => <h5 className="px-6">{children}</h5>,
15 h6: ({ children }) => <h6 className="px-6">{children}</h6>,
16 p: ({ children }) => <p className="mb-4 px-6">{children}</p>,
17 ol: ({ children }) => (
18 <ol className="list-decimal mt-4 list-inside my-8 px-6">{children}</ol>
19 ),
20 img: (props) => (
21 <Image
22 sizes="100vw"
23 width={0}
24 height={0}
25 className="shadow-lg rounded-lg"
26 style={{ width: "100%", height: "auto" }}
27 {...(props as ImageProps)}
28 />
29 ),
30 ...components,
31 };
32}
There's probably a better way I could have worked out to add the padding I want (this padding is so that the horizontal line on the header is slightly larger than the width of the content) but this was a pretty quick way to solve the problem.
With the MDX plugin, your markdown will be converted to HTML tags, and this useMDXComponents
function allows you to map those HTML tags to whatever you want. I've added some basic
styling to my header tags and ordered lists, and I've also mapped the img
tag to
the Next.js Image
component.
The next thing I wanted to add was a nice way to format text for the "Published" text at the top of each article.
Talking about this format...
I found I can add any arbitrary tag to this list and then use that tag in my markdown files.
So I added a Accent
tag so that I can format this the way I want.
/mdx-components.tsx
1import type { MDXComponents } from "mdx/types";
2import Image, { ImageProps } from "next/image";
3
4export function useMDXComponents(components: MDXComponents): MDXComponents {
5 return {
6 ...,
7 Accent: ({ children }) => (
8 <p className="mb-8 text-theme-6 text-md px-6">
9 <i>{children}</i>
10 </p>
11 ),
12 ...components,
13 };
14}
Now I can use this tag in my markdown files like so:
1# Markdown, Please 2 3<Accent>Published Feb 21st, 2025</Accent> 4 5I knew from the beginning making this website that I'd want the ability...
I also added a tag for my Note sections:
/mdx-components.tsx
1import type { MDXComponents } from "mdx/types";
2import Image, { ImageProps } from "next/image";
3
4export function useMDXComponents(components: MDXComponents): MDXComponents {
5 return {
6 ...,
7 Accent: ({ children }) => (
8 <p className="mb-8 text-theme-6 text-md px-6">
9 <i>{children}</i>
10 </p>
11 ),
12 Note: ({ children }) => (
13 <div className="px-6">
14 <div className="my-8 p-4 bg-theme-6 text-theme-1 font-semibold flex rounded-lg">
15 <div className="mr-4 font-bold">Note:</div>
16 <div>{children}</div>
17 </div>
18 </div>
19 ),
20 ...components,
21 };
22}
You will get a React error if you don't make these custom tags start with a capital letter.
Then all I had to do was convert my one article I had written to markdown! Bonus value that it's now much easier to read these pages in GitHub.