MDX, Tailwind & Syntax Highlighting in NextJS Pages-Routing
February 06, 2023 - 11min - #mdx #tailwindtypography #rehype #webdev #tutorial
Setting up MDX in NextJS can be a bit of a struggle. Especially when you mix it with Tailwind and Rehype Pretty Code, which at times interfere. Here is how you can set them up together in near harmony.
Table of Contents
- Prerequisites
- MDX Setup
- Tailwind Typography
- Rehype Pretty Code
- MDX Custom Elements
- Custom Colortheme
0. Prerequisites
You must have already either followed the steps of this guide:
How to Code a Blog in 2025 (with MDX in Next 14 Pages-Routing)
Or have scanned through it to make sure the state of your project lines up with it:
- The NextJS installation settings,
- the pages-routing setup,
- and the HomeFeed component should be exactly the same.
1. MDX Setup
Start with the basic installation:
Now to the config file, with a little bummer. The NextJS docs show an outdated version of the configuration settings:
All other plugin configs that you need to make MDX working use ESM module imports. So you have to translate it into ESM syntax like this:
Note: For NextJS to recognize the config to be in "module mode", you have to also change the file-ending to .mjs.
A big part in making the whole setup work, is to understand how the config file works, so you can consciously re-adjust from there.
If you should get stuck anyway, I can recommend to follow the steps again in a from-scratch NextJS project.
Note for beginners: You can set that up really fast in a separate IDE workspace and run both your main and your experimentation project at the same time.
Remark Frontmatter Plugin
Now you should be able to see your .mdx pages via
localhost:3000/posts/blog-post-title.mdx
. However, the frontmatter metadata
section gets rendered aswell and ruins the start of the article. To hide it,
install remark-frontmatter
:
And update the config:
2. Tailwind Typography Setup
Now the metadata is hidden and you should only see the content of the markdown page.
The next thing to notice is that there is no markdown formating: ##h2
- li
>blockquote
etc aren't showing as they should. That's because Tailwind resets
all styles, including markdown elements.
You have to install the
Tailwind Typography Plugin
and apply its prose
-classes to your .mdx pages, to revive the markdown
functionality.
Install via npm:
And add the plugin to your tailwind.config.js
file:
Now, to actually apply the typography plugin styles (className="prose"
) to
your mdx page, you need to set up an MDXPage
component, and an MdxLayout
component.
Explanation of classes (line by line):
- general
<main>
settings related to height, width, positioning etc - "activate" prose for all posts, set grayscale tone, enable darkmode
- customizations for markdown elements
Check out the Tailwind Typography Docs for all styling options.
Now, its time to mount MdxLayout
. Below the frontmatter, and above your
content of each .mdx file insert this MDXPage
component:
Now you should finally see markdown behaviour as usual. Congratulations!
3. Rehype Pretty Code
Every dev blog needs proper codeblocks. A great syntax highlighter for this projects tech stack is Rehype Pretty Code.
Install via npm:
And setup in next.config.mjs
:
Now your codeblocks should be pretty, let's go!
4. MDX Custom Elements
There is a lot you can customize via Tailwind Typography, but for some markdown components you might want extra control.
Just create an mdx-components.js
file like this in your root folder, and
NextJS will recognize it:
Even if you don't have customizations in mind yet, make sure to set up at least the empty component already, you will likely run in to trouble without it later.
At this point we have TailwindCSS, Tailwind Typography, Vanilla CSS and Markdown
(and Prettycode) intermingling. I am pretty sure that's the reason, why
sometimes, Tailwind classes don't work in mdx-components.js
.
I have not found a direct solution for that, but you can cope by using
inline-styles CSS (see <hr/>
) or by customizing MDX components via Tailwind
Typography in MdxLayout.js
.
Codeblock Customization: You might notice, that some codeblock
customizations via prose-pre:
in MdxLayout
do not work. I have not found the
reason why, but I found a way to make it work: Insert
pre: ({children})=> <pre>{children}</pre>,
as an unstyled custom component.
You should now be able to use all prose-pre:
customizations.
MDXProvider: Some tutorials also tell you to use an <MDXProvider>
for
custom components, but that is not neccessary and critizised by the
MDX Docs. Instead, just set up
the mdx-components.js
file like explained, and have <MDXProvider>
(@mdx-js/react
) NOT installed.
5. Custom Colortheme
Parallel to the blog, I created a custom colortheme to use in VS Codium. I used this buggy, but cool themegenerator on vscode.one.
Unfortunately I found out afterwards, that it is not compatible with the newest
versions of VS Code. However, I could at least use it for this blog, by
importing it via fs
:
Be careful when creating your own theme with that tool: Saving only works every once in a while...
Also, changes that you make manually in the .json
after loading into rehype
only show up after replacing it with another theme eg.
rehypePlugins: [[rehypePrettyCode,{theme:'one-dark-pro'}]],
and then
reimporting your updated custom theme again.
I hope this saves you from having days of frustration. If it does - feel free to subscribe below:)