Include React Components in MDX Content
This is part 5 in the Build a Blog with Next, MDX, and Tailwind series
Markdown is great, but we’re using MDX so we get the added benefit of being able to include React components in our content. In this installment of the Build a Blog with Next, MDX, and Tailwind series, we’ll create a React component to include in our MDX content. We’ll also use that same mechanism to replace a standard HTML
tag with our own version with our own styling applied with Tailwind.
Building the “Hot Tip” React Component
We’re going to build a component so we can call out and highlight tips in our content. We’ll start with a HotTip.tsx
file in our components directory.
import { FunctionComponent } from 'react'
export const HotTip: FunctionComponent = ({ children }) => {
return (
<div>
<div>🔥 Hot Tip!</div>
<p>{children}</p>
</div>
)
}
We’re adding a bit of markup around children
, so we’ll use HotTop
by wrapping some content with it like <HotTip>important message here</HotTip>
. Let’s apply some styling so it serves a purpose.
Let’s look at the styled version and we’ll just quickly touch on the styles that have been applied.
import { FunctionComponent } from 'react'
export const HotTip: FunctionComponent = ({ children }) => {
return (
<div className="p-3 bg-orange-50 border-4 border-orange-400 rounded-lg">
<div className="text-2xl font-extrabold text-orange-500">🔥 Hot Tip!</div>
<p className="font-medium">{children}</p>
</div>
)
}
The structure of the component has remained the same. We’ve added a subtle background to the wrapping div
, and put a thick orange border with rounded corners around the div
. We’ll bumped up the font weights and size for both the “Hot Tip!” title and the paragraph that will wrap the children
content.
Expose the Component to MDXRemote
Now that we have our component built, we need to expose it to the MDXRemote
component in pages/blog/[slug].tsx
.
Let’s add an import for our new component
import type { GetStaticPaths, GetStaticProps } from 'next'
import { getAllPostSlugs, getPostBySlug } from '../../utils'
import { MDXRemoteSerializeResult } from 'next-mdx-remote/dist/types'
import { MDXRemote } from 'next-mdx-remote'
+import { HotTip } from '../../components/HotTip'
And then right below our imports, we can create a components
object. We’ll include HotTip
using the shorthand syntax.
const components = {
HotTip,
}
Now we’ll pass this components
object along to our MDXRemote
instance.
<article className="prose prose-xl prose-sky mx-auto mt-2 py-4">
- <MDXRemote {...mdxSource} />
+ <MDXRemote components={components} {...mdxSource} />
</article>
Using HotTip in the Content
Now that we’ve created our component and made it available, let’s use it in some content and see the results. I’m going to test this out in the content/hello-world.md
file. The 4th paragraph is fairly short, so I’m just going to wrap that in the new HotTip
component.
+<HotTip>
It takes dark in order to show light. Nothing wrong with washing your brush. You can do anything here - the only pre-requisite is that it makes you happy. You're meant to have fun in life.
+</HotTip>
At this point, you should see this “Hot Tip” being called out in your content!
Replacing Standard HTML
Now that we’re providing a components
object to MDXRemote
, we can use that to replace any markup we want. In an upcoming post, we’ll see other ways to use this functionality in pretty powerful ways. For now, let’s look at a small example just to cover the general idea.
In my content/hello-world.md
, I added a small bit of formatting in the first sentence
Maybe there's a **happy little bush** that lives right there.
When that is converted to JSX, it renders
Maybe there's a <strong>happy little bush</strong> that lives right there.
The Tailwind typography plugin does a great job of styling this for us, but just for the purposes of this exercise let’s replace it so we can apply our own styling.
Back in pages/blog/[slug].tsx
, let’s update our components
object to include a strong
key with a custom component defined for it.
const components = {
HotTip,
+ strong: ({ children }) => (
+ <strong className="text-orange-500 font-bold">{children}</strong>
+ ),
}
And that’s it. When the MDX is rendered, any instance of a strong
element will use the version we supplied instead.
As I alluded to earlier, we’ll use this capability later to add some optimizations to our blog.
The examples we used here were very focused on superficial styling changes, but we can use more interactive React components in the same way. You could, for example, add a component with a form that accepts input, tracks internal state and all the usual interactivity you expect from React components.
Check back next week for the next article in the series, Improve Blog Listing with Post Excerpts!