React Mdx
React-docgen grabs any JS Docblocks you write for your React classes/functions (Button.js), as well as the Prop Types. These are displayed on your documentation page, with the props displayed in a table. Inside your MDX file you can write additional documentation with JSX examples.
In this post i'm going to discuss the term 'Fold it in' which I think was first coined byspences10 and it relates to a method of using React Components inMDX without the need to import them each and every time.
- The MDX file format mixes Markdown with JSX. We can use Markdownโs succinct syntax for our documentation. Storybook will compile the Markdown and JSX together into a document. We create a MDX file with the stories.mdx to create our documentation. For example, we can write: Button.stories.mdx.
- So I desire to turn all that mess into a react component and feed it data in the preceeding manner, or something similar, that is keeping with the spirit of Markdown/YAML/MDX. I suppose I could feed the components props of arrays and objects filled with strings, but I would like to be able to keep the simple YAML/Markdown feel, even inside an.
This term may or may not make 100% sense but naming things is hard and having a shorter way to describe an approach ormethod in my experience can be quite helpful, but whatever, 'you do you'
On a recent stream with my NatterPops chums we implemented MDX in Benedicte's blog and wedid attempt to explain what we meant by 'fold it in' You can watch that below.
In an attempt to explain a little more i've documented a couple of ways this approach can be used.
In this example i'll be specifically referring to methods I use in my Gatsby builds when working with MDX
MDX
For those not familiar with MDX it's similar to Markdown and additionally provides a method to render React componentsalong with typical Markdown syntax... MDX is brilliant and I love it!
Here's an example ๐
This will result in something like the below ๐
This is a heading written in markdown
This is the body written in markdown
And this is a React component ๐
This is a quote - from someone
You'll see near the top of some-blog-post.mdx
there's a familiar looking import
statement, this is pretty much whatyou'd expect to see if you were in Jsx land.
The import
statement works the same way in MDX and allows you to import React components and render them alongside theusual Markdown syntax, but because it's a React component you can be a little more fancy. In this example i've addedx2 Svg quote icons either side of the text.
This approach works great for 'one off' components but in the case of the <CustomBlockquote />
you might want to useit more regularly when writing blog posts and having to import it for each and every MDX file can be a bit of a faff.
Fold it in
It's at this point where you might like to think about providing all MDX files with the ability to render the<CustomBlockquote />
component without needing to import it first. It's here where the term 'fold it in' makes a bitmore sense.
By 'folding' the component in to the <MDXProvider />
it will be ready to use by any MDX file without the need toimport it first.
Your implementation of MDX will likely be different to mine but you will probably have an <MDXProvider />
somewhere inyour project. Here's a stripped back MDX Template file.
MDXProvider
To 'fold' components into MDX I use the components
prop on the <MDXProvider />
and pass in the components i'd liketo make available to all MDX files.
Now that the <CustomBlockquote />
component has been 'folded' in there's no need to import it in the MDX blog post.
I've been asked a number of times about how this might affect bundle size / page size because using this method bundlesthe <CustomBlockquote />
component with each page regardless of if it's being used or not.
I have to be honest I don't know if that's actually the case. My assumption would be that webpack is smart enough toknow if a component is in use or not and therefore would only bundle the <CustomBlockquote />
as and when it'srequired but that's all a bit low level for me.
If you have questions surrounding the potential performance impacts of using this approach you might like to ask eitherChris Biscardi or John Otander, they're both veryapproachable chaps and were heavily involved in the creation of MDX.
However, if you have any other questions i'll do my best to answer them!
MDXRenderer
In the above example i'm using the <MDXProvider />
from @mdx-js/react
and passing in a React component, in this nextbit i'm going to use the <MDXRenderer />
from gatsby-plugin-mdx
to fold in 'data'.
I'll use the <CustomBlockquote />
component again but this time rather than rendering it's children i'm going to passdata stored in frontmatter
back through the <MDXRenderer />
and make it available as a prop
in the MDX body ๐ฅด
Frontmatter
First I add a new field in frontmatter
called quotes
, it's of type array
but looks like a list syntax in Markdown.If the below diff is a little hard to read, the quotes
field should look like this, the ---
are important as theysignify the beginning and end of frontmatter
Props instead of children
This is a weird one, but notice now instead of rendering the children of <CustomBlockquote />
as text I'm using anescaped Jsx syntax and pointing it to props.quotes[0]
Mdx React Native
The [0]
is normal array syntax and represents an index from an array
MDXRenderer Props
React Mdx Example
In order for props.quotes[0]
to equal something other than null
I now query the frontmatter
from the MDX Templatefile and pass the quotes
back to the <MDXRenderer />
on a prop i've also called quotes
React Mdx Tutorial
This is a slightly contrived example but I suppose it might be useful if you had a really long blog post with lots ofquotes and rather than having to scroll through the page and find one that might need editing you could find the quotein question by looking at the top of the file in the frontmatter
. ๐คทโโ๏ธ
A more 'Real World' example of how the <MDXRenderer />
can be used to pass data from frontmatter
back to the MDXbody
can be see in this rather outdated post: MDX Embedded Images.
In this post I pass local image files from frontmatter
, process them withchildImageSharp
in the MDX Template before passing them back to the <MDXRenderer />
to display them anywhere in theMDX body.
Phew... that just about wraps things up... see you around ๐บ