DEV Community

Cover image for How to built a static site React Router v7 + MDX
Miguel Quintal
Miguel Quintal

Posted on

How to built a static site React Router v7 + MDX

Tired of overcomplicated static site generators? Want to build your docs, blog, or site using just React Router v7 + MDX? Meet react-router-mdx — a small but powerful tool to generate static web sites. Check out our demo page


🧠 Why react-router-mdx?

Well, it keeps the process of creating static web pages based on MDX simple. No need for vite plugins and other dependencies. You just need to install it, setup where your MDX files are and viola!

That is where react-router-mdx comes in:

🔥 Automatic MDX route generation from a folder and file naming

🧩 Fully compatible with React Router v7 (Framework mode)

🛠️ Minimal setup — no custom compiler or extra dependencies

📦 SSR/Pre-rendering using react-router build


🚀 Installation

Make sure you're using React Router v7 (Framework mode). Once you have generated the React Router project your project's folder structure should look like:

my-amazing-webpage/
├── public/
├── app/
│   ├── home/
│   ├── routes/
│   │   └── home.tsx
│   ├── root.tsx
│   ├── routes.tsx
│   └── app.css
├── .gitignore
├── package.json
├── react-router.config.ts
├── tsconfig.json
└── vite.config.ts
Enter fullscreen mode Exit fullscreen mode

Using yarn

yarn add react-router-mdx
Enter fullscreen mode Exit fullscreen mode

Using npm

npm install react-router-mdx
Enter fullscreen mode Exit fullscreen mode

🛠️ Set it up

1- Change your react-router.config.ts to init the and provide the pre-rendered paths.

Your react-router.config.ts should look like:

import type { Config } from "@react-router/dev/config";
import { init } from "react-router-mdx/server";


const mdx = init({ path: "posts" });

export default {
  ssr: true,
  async prerender() {
    return ["/", ...(await mdx.paths())];
  },
} satisfies Config;
Enter fullscreen mode Exit fullscreen mode

The path passed to the init should the folder where you'll keep your MDX files.

2- Create hello-world.mdx file under posts directory:

posts/
└─ hello-world.mdx
Enter fullscreen mode Exit fullscreen mode

posts/hello-world.mdx

---
title: hello world title
---
# hello world

This is a hello World mdx file
Enter fullscreen mode Exit fullscreen mode

3- Add MDX routes to your app/routes.ts

import { index } from "@react-router/dev/routes";
import { routes } from 'react-router-mdx/server'

export default [
    index("routes/home.tsx"),
    ...routes("./routes/post.tsx")
]
Enter fullscreen mode Exit fullscreen mode

4- Add MDX routes to your app/routes/posts.ts

import { loadMdx } from 'react-router-mdx/server'
import { useMdxComponent } from "react-router-mdx/client"
import type { Route } from "./+types/post";

export const loader = async ({ request }: Route.LoaderArgs) => {
  return loadMdx(request)
}

export default function Home() {
  const Component = useMdxComponent()
  return (
    <Component />
  );
}
Enter fullscreen mode Exit fullscreen mode

Now if you run yarn dev you should have the page based on posts/hello-world.mdx on http://localhost:/posts/hello-world


🙌 Conclusion

If you're building a React Router v7-based site and want Markdown + React support with minimal friction, give react-router-mdx a shot. It's ideal for:

📚 Documentation sites

📝 Personal blogs

🧪 Component previews / style guides

Let me know what you build with it — contributions and feedback welcome!

Top comments (6)

Collapse
 
baronadams profile image
Kouyang Roger Adam's

I still have one concern: the table that is supposed to contain the paths to the mdx articles is empty. Here is my react-router.config.ts file :

import type { Config } from "@react-router/dev/config";
import { init } from "react-router-mdx/server";


const mdx = init({ path: "posts" });

export default {
  ssr: true,
  async prerender() {
    let mdxPaths = await mdx.paths();
    console.log(mdxPaths); // print an empty array
    return ["/", ...mdxPaths];
  },
} satisfies Config;
Enter fullscreen mode Exit fullscreen mode

But I have the hello-world.mdx file in /posts directory

Collapse
 
mquintal profile image
Miguel Quintal

It had an issue while running on a Windows machine. The fix was published on version 1.0.7. Please make sure you are using that version. Thanks 👍

Collapse
 
baronadams profile image
Kouyang Roger Adam's

Great! It worked. Now, how do you add external plugins to your mdx module, such as rehype and remark?

Thread Thread
 
mquintal profile image
Miguel Quintal

Currently is not possible to provide external plugins, anyway it should be an easy change. Can you please create an issue on github with this so we can keep this request on track. Thank you.

Collapse
 
xantel profile image
Gennadiy Bobrov

same here, just empty array of paths

Collapse
 
baronadams profile image
Kouyang Roger Adam's

Very great 👌! It's exactly what I was looking for, thank you 🙏