May 11, 2020
MDX lets us use React Components in Markdown files using next-generation tooling. Fenced Code Blocks have some unique extensibility points for exposing new functionality from our .mdx
files.
From the MDX site,
MDX is an authorable format that lets you seamlessly write JSX in your Markdown documents. You can import components, such as interactive charts or alerts, and embed them within your content. This makes writing long-form content with components a blast 🚀.
Markdown lets us write documentation in human-readable and computer-readable formats. Simple formatting is converted to HTML.
A simple Markdown (.md
) file may look like this:
#### Hello, _world_!
This is an example of text in Markdown.
- Red
- Green
- Blue
This is an example of text in Markdown.
A simple MDX (.mdx
) file may look like this:
#### Hello, _world_!
Below is an example of JSX embedded in Markdown.
<div style={{ padding: "20px", backgroundColor: "#B71C1C" }}>
<h3>This is JSX</h3>
</div>
Below is an example of JSX embedded in Markdown.
MDX can be great, but as you can see, we can lose some of the flexibility and readability markdown has made us believe.
Take the following .mdx
:
import BundlephobiaInline from "bundlephobia-inline";
<BundlephobiaInline packageName="react-query" />
<BundlephobiaInline packageName="react-table" />
<BundlephobiaInline packageName="react" />
<BundlephobiaInline packageName="react-dom" />
<BundlephobiaInline packageName="dayjs" />
<BundlephobiaInline packageName="styled-components" />
This has turned a simple list of packages into an overly verbose list of code. I'd much rather use something like this
```bundlephobia
react-query
react-table
react
react-dom
dayjs
styled-components
```
Using the <MDXProvider components={components} />
, we can customize any code
blocks with a custom React component.
import { MDXProvider } from "@mdx-js/react";
const components = {
pre: (props) => <div {...props} />,
code: Code,
};
Let's take a look at how <Code />
works, and what props get passed.
```bundlephobia include-links=true
react-query
```
children
as the content
react-query
className
with language-*
language-bundlephobia
metastring
withWith a little trickery, we can overload the language-
value being passed in to short-circuit the Code
return value for the unique scenarios:
function Code(props) {
const { children: codeString = "", metastring = "", className = "" } = props;
const language = className.replace(/language-/, "");
//
// If we see "bundlephobia" fenced code block
//
if (["bundlephobia"].includes(language)) {
const lines = codeString.trim().split(/[\n\r]+/);
return (
<>
{lines.map((line) => (
<div>
<Bundlephobia key={line} packageName={line} />
</div>
))}
</>
);
}
// ...
}
Here's it running in action:
```bundlephobia
react-query
react-table
react
react-dom
dayjs
styled-components
````
// ```chart type=bar
Green Team=[1,2,3]
Blue Team=[3,4,2]
vs
<Chart
records={[
{ label: "Green Team", data: [1, 2, 3] },
{ label: "Blue Team", data: [3, 4, 2] },
]}
/>
// ```map
Groom Lake, Nevada
vs
<Map address="Groom Lake, Nevada" />
Further reading...