August 19, 2023
How to Create a Blog Page with Syntax Highlighting
Learn how to set up a blog page with syntax highlighting in Next.js using gray-matter, next-mdx-remote, rehype-prism-plus, and a custom Prism.js CSS theme.
In this tutorial, we will learn how to create a blog page with syntax highlighting using the following libraries:
gray-matter
for front matter extractionnext-mdx-remote
for rendering MDX contentrehype-prism-plus
for syntax highlighting- A custom Prism.js CSS theme from PrismJS Themes Repository
Warning: In this tutorial, I use old version of
Next.js
andMDX
library. If you use the latest version, you may need to adjust the code accordingly. Visit my old personal blog repository to see the full code.
Table of Contents
Prerequisites
Set Up Your Next.js Project
Assuming you already have a Next.js project set up, navigate to the project directory and install the required dependencies:
npm install gray-matter next-mdx-remote
# or
yarn add gray-matter next-mdx-remote
# or
pnpm add gray-matter next-mdx-remote
Create MDX Files
Create a directory to store your MDX files. For example, you can create a posts
directory in the src
directory of your Next.js project. Create an MDX file in the posts
directory:
# Simple Syntax Highlighting Example
```ts
const greeting: string = "Hello, World!";
console.log(greeting);
```
Configure Front Matter
Use gray-matter
to extract front matter (metadata) from your MDX files. Front matter typically includes information like the title and date of the blog post. Create an MDX file with front matter like this:
---
title: "Simple Syntax Highlighting Example"
date: "2023-08-19"
// ... other front matter fields
---
# Simple Syntax Highlighting Example
```ts
const greeting: string = "Hello, World!";
console.log(greeting);
```
Create a Blog Page
Next, create a page to display the blog post. Create a file called index.js
in the pages/blog
directory:
// Import the required libraries
import NextLink from 'next/link'
import matter from 'gray-matter'
import path from 'path'
import fs from 'fs'
// Create a Blog component
const Blog = ({ posts }) => {
console.log(posts);
// Render the blog posts
return (
<div>
{posts.map((post) => ( // Map through the posts
<div key={post.slug}>
<h2>{post.frontMatter.title}</h2>
<p>{post.frontMatter.date}</p>
<NextLink href={`/blog/${post.slug}`}>
Read more
</NextLink>
</div>
))}
</div>
)
}
export default Blog
// Fetch the blog posts at build time
export const getStaticProps = async () => {
// Get the file paths of the MDX files in the posts directory
const postFilePaths = fs.readdirSync(path.join(process.cwd(), "src", "posts"));
// Map the file paths to the posts
const posts = postFilePaths.map((path) => {
const postFilePath = path.join(process.cwd(), "src", "posts", path);
const source = fs.readFileSync(postFilePath);
// Extract the front matter from the MDX file
const { content, data } = matter(source);
return {
slug: path.replace(/\.mdx/, ""),
frontMatter: {
slug: path.replace(/\.mdx/, ""),
...data
}
}
});
// Return the posts as props
return {
props: {
posts
}
}
}
Render MDX Content
Use next-mdx-remote
to render the MDX content. Create a file called [slug].js
in the pages/blog
directory:
// Import the required libraries
import { MDXRemote } from 'next-mdx-remote'
import { serialize } from 'next-mdx-remote/serialize'
import matter from 'gray-matter'
import path from 'path'
import fs from 'fs'
// Create a BlogPost component
const BlogPost = ({ source, frontMatter }) => {
return (
<div>
<h1>{frontMatter.title}</h1>
<p>{frontMatter.date}</p>
<MDXRemote {...source} />
</div>
)
}
export default BlogPost
// Fetch the blog post at build time
export const getStaticProps = async ({ params }) => {
// Get the file path of the MDX file
const postFilePath = path.join(process.cwd(), "src", "posts", `${params.slug}.mdx`);
const source = fs.readFileSync(postFilePath);
// Extract the front matter from the MDX file
const { content, data } = matter(source);
// Serialize the MDX content
const mdxSource = await serialize(content);
// Return the blog post as props
return {
props: {
source: mdxSource,
frontMatter: data
}
}
}
// Fetch the paths of the blog posts at build time
export const getStaticPaths = async () => {
// Get the file paths of the MDX files in the posts directory
const postFilePaths = fs.readdirSync(path.join(process.cwd(), "src", "posts"));
// Map the file paths to the paths
const paths = postFilePaths.map((path) => ({
params: {
slug: path.replace(/\.mdx/, "")
}
}));
// Return the paths
return {
paths,
fallback: false
}
}
Now you can navigate to the blog page and see the blog post. However, the code snippet is not highlighted. Let's add syntax highlighting to the code snippet.
Add Syntax Highlighting
Use rehype-prism-plus
to add syntax highlighting to the code snippet. First, install the rehype-prism-plus
package:
npm install rehype-prism-plus
# or
yarn add rehype-prism-plus
# or
pnpm add rehype-prism-plus
Next, update the [slug].js
file to use rehype-prism-plus
plugin to serialize the MDX content:
// ... other imports
import rehypePrismPlus from 'rehype-prism-plus'
// ... other code
// Fetch the blog post at build time
export const getStaticProps = async ({ params }) => {
// ... other code
// Serialize the MDX content with rehypePrismPlus
const mdxSource = await serialize(content, {
mdxOptions: {
rehypePlugins: [rehypePrismPlus]
}
});
// ... other code
}
The code snippet in the blog post is now highlighted. However, the style of the syntax highlighting is not applied. Let's apply the Prism.js CSS theme to your Next.js project.
Style Syntax Highlighting
Apply the Prism.js CSS theme to your Next.js project. You can import the CSS file in your project's main CSS file or directly in your component, You can find the CSS file in the PrismJS Themes Repository.
import 'path-to-your-prismjs-theme.css'
Conclusion
In this tutorial, we learned how to create a blog page with syntax highlighting using Next.js, MDX, and Prism.js. We set up our project, configured front matter, rendered MDX content, and added stylish syntax highlighting for code snippets.
Now you can create a blog page with syntax highlighting for your Next.js project.
Happy coding 🚀!