Creating a Blog with MDX and Tailwind CSS in Next.js

Blockchain

Want to write blog posts using simple Markdown, but with the power of React components? That's where MDX comes in. Combine it with Tailwind CSS and Next.js, and you’ve got a clean, fast, and flexible blog setup no clunky CMS needed.

🧰 Prerequisites

Before we start, make sure you have the following ready:

  • A Next.js project set up

  • Tailwind CSS installed and configured

  • Basic understanding of React/Next.js and routing

🤔 What is MDX, and Why Use It?

Think of MDX as Markdown with superpowers.

Regular Markdown is great for writing, but it's limited no custom components, no interactivity. MDX fixes that by letting you mix Markdown and JSX.

So you can write a blog post like this:

# Hello World

This is a paragraph.

<MyCustomComponent />

It feels like writing Markdown, but you can use React components inside it. Neat, right?

🛠️ Step 1: Install MDX Support

Next.js doesn't support MDX out of the box, but it's easy to add.

Install the following packages:

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

Then, update your next.config.js file with below code. This tells Next.js to treat .mdx and .md files like pages or components.:

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'],
}
 
const withMDX = createMDX({
  // Add markdown plugins here, as desired
  extension: /\.(md|mdx)$/,
})
 
// Merge MDX config with Next.js config
export default withMDX(nextConfig)

📦 Step 2: Add mdx-components.tsx to Customize MDX Rendering

To globally control how MDX content is rendered in your app, create a file called mdx-components.tsx

Place it in your project root — ideally at the same level as app/ or src/.

📁 Your project might now look like:
⁠
/app
/mdx-components.tsx
/package.json

Now, open mdx-components.tsx and add the following code:

import type { MDXComponents } from 'mdx/types'
 
const components: MDXComponents = {
⁠    // Example: Custom style for <h1> tags
    h1: ({ children }) => (
      <h1 className="text-3xl font-bold text-blue-600 mb-4">{children}</h1>
    ),

    // You can add more custom elements here...
    // p: ({ children }) => <p className="leading-relaxed">{children}</p>,
    // a: ({ href, children }) => <a className="text-blue-500 underline" href={href}>{children}</a>
}
 
export function useMDXComponents(): MDXComponents {
  return components
}

This file tells Next.js:

“Whenever I use MDX, here’s how I want my components like <h1>, <p> and <a> to look.”

You can keep it simple at first or customize everything later as your design grows.

💡 This is especially useful if you want your blog posts to match the design system in your templates (colors, fonts, spacing, etc.).

📁 Step 3: Organize Your Blog Content

Let’s create a simple folder structure for your blog:

/blog
  └── hello-world.mdx

Inside hello-world.mdx, add your first post:

# Hello World 👋

Welcome to my blog built with MDX, Tailwind, and Next.js!

This is a sample post.

🖼️ Step 4: Create a Blog Layout

We’ll use a basic layout component to wrap our posts.

Create a file: components/BlogLayout.js

export default function BlogLayout({ children }) {
  return (
    <main className="prose prose-lg mx-auto px-4 py-10">
      {children}
    </main>
  );
}

prose is a Tailwind class from @tailwindcss/typography that styles content beautifully. Make sure it's added in your Tailwind config!

Now, use this layout in your MDX page:

import BlogLayout from '../components/BlogLayout'

export default ({ children }) => <BlogLayout>{children}</BlogLayout>

# Hello World 👋

This post is using a custom layout!

💡 Tip: Reuse Layout Automatically

If you don't want to wrap every MDX file manually, you can load layout globally using getLayout pattern or page-level wrappers but for simplicity, manual import works just fine for now.

🎨 Step 4: Style It Up with Tailwind

Want to add a dark mode? Or tweak fonts, spacing, or colors?

Tailwind makes it easy:

<main className="prose dark:prose-invert ...">

You can customize everything directly in your globals.css to match your blog’s style or save time using a pre-built template (😉 more on that below).

🧪 Bonus: Add a Component Inside Your Blog

Try this inside your .mdx file:

import Alert from '../components/Alert'

# Welcome!

Here's a custom component below:

<Alert message="This is a custom alert inside MDX!" />

MDX lets you turn your blog into more than just text. You can add:

  • YouTube embeds

  • Charts

  • Interactive UI

  • Anything React can do!

✅ You Now Have a Functional Blog

You’ve just:

  • Set up MDX in Next.js

  • Styled content with Tailwind's prose classes

  • Added custom components inside blog posts

That's a powerful combo for writing content and building a flexible site.

🌟 Want to Save Time?

If you're building with Next.js and Tailwind CSS, and want to skip the design and layout work, we’ve got you covered.

Our premium templates are:

  • Built with clean Next.js + Tailwind CSS

  • Easy to customize

  • Fully responsive and production-ready

Whether you're working on a portfolio, landing page or startup site these templates help you go live faster, without starting from scratch.

👉 Check our templates now

Recent blog

House
The Ultimate Website Copywriting Guide: What to Say on Each Page

What to write on every page of your website from homepage to contact. Clear, actionable copy tips with real examples.

House
How Next.js & Tailwind CSS Are Redefining Web Development in 2025

Next.js & Tailwind CSS are redefining web dev in 2025. Discover why this stack powers our modern, ready-to-use templates built for speed and scalability.

House
How Ready to Use Website Templates Help Startups Save Time & Money

Learn how ready to use website templates help startups save time, reduce costs, and launch faster so you can focus on growing your business.

House
Everything You Need to Know About PHP 8.5's New Features

Explore new PHP 8.5’s features pipe syntax, attributes on constants, NoDiscard, CLI enhancements, Intl tools and more simplified and easy to understand.

Nodejs
js
wordpress
tailwind
figma
bootstrap
html
nuxt
angular
react
vuejs
nextjs

Stay updated with our weekly newsletter

No Spam. Only high quality content and updates of our products.

Join 20,000+ other creators in our community

Discount image