MDX syntax can be boiled down to being JSX in Markdown. It’s a superset of Markdown syntax that also supports importing, exporting, and JSX. - mdxjs.com
Why do we need MDX, what's wrong with our "traditional" markdown?
Well, if you don't already know: Modular = Good. Monolithic = Bad. 👌
That's true for our code and that's also true for our content. Building with components, whether they are code or markdown, means easier maintainability and better reusability. All that translates to many other things like consistency in tech/ UIUX/ "voice & tone"/ everything).
MDX also makes it possible to incorporate JSX into our markdown and even build a design system to customize its styling(!)
Demo: Using MDX with Bit
To fully enjoy the great merits of component-driven markdown, we'll publish all markdown components and all (styling) React components, to Bit.
Bit is a tool and a component hub that makes publishing, documenting, and organizing components, quick and simple.
Bit doesn't require our project to be structured in any specific way. We simply publish independent components from... wherever.
Combining MDX with Bit means we don't have to work too hard to make our MDX/styling components available for reuse in other projects.
Our steps to composing a document and sharing its components:
Create a Gatsby blog site and set it up to use MDX
Write a few MDX markdown files (components)
Build a few React components for our markdown styling
Compose everything together into a single document
Publish both React and MDX components to Bit
These should be our end results:
The document
Our published components on Bit.dev
Let the coding begin!
1. Create a Gatsby blog site and set it up to use MDX
We'll start with the 'gatsby-starter-blog' starter
$ gatsby new gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blog
Then, install all necessary MDX packages
$ npm install gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react
Configure Gatsby's gatsby-config.js
file to use the MDX plugin. Also, we'll set the .md
\ .mdx
as the extensions that should be handled.
plugins: [
{
resolve: `gatsby-plugin-mdx`,
options: {
extensions: [`.mdx`, `.md`]
},
},
// more plugins...
2. Write a few MDX markdown components
We'll create a src/components/content
directory for all our markdown components. Check out the markdown files here.
For this demo, we'll make sure to use the paragraph
, header1 #
, header3 ###
, link []()
, and code
markdown elements. We will customize their styling, later on.
3. Build a few React components for our markdown styling
In this step, we'll create a few UI components using styled-components. We'll place our components in a new src/components/markdown-styles/
directory.
These components will make up what would essentially be our markdown design system.
For now, we'll simply build them - don't worry if it's not clear yet how they should actually be used for styling. It will all be cleared up, in our next step.
So, for example, our CodeBlock
component that would later serve to style our markdown code
element, will look like so:
import styled from 'styled-components'
const CodeBlock = styled.pre`
@import url(a-url-to-google-fonts);
font-family: 'Source Code Pro', monospace;
background-color: #000;
color: #fafafa;
padding: 20px;
border-radius: 5px;
display: block;
overflow-x: auto;
margin-right: 25px;
margin-left: 25px;
`
export default CodeBlock;
4. Compose everything together into a single document
As mentioned at the beginning of this tutorial - MDX files can be exported and imported. Notice how there's no export x from 'path'
statement - you simply write the document and it's available for import
.
To compose our two markdown components into a single document we'll import them to the src/pages/index.js
file (this will be our one-and-only document)
import React from 'react'
import ParagraphDefinition from '../components/content/ParagraphDefinition.md'
import ParagraphDefinitionHTML from '../components/content/ParagraphDefinitionHTML.md'
const Document = () => {
return (
<>
<ParagraphDefinition />
<ParagraphDefinitionHTML />
</>
)
}
export default Document;
We'll then wrap the MDX components with the MDXProvider
context so that we could pass props for styling, down this markdown-component tree.
// imports...
import {MDXProvider} from '@mdx-js/react'
const Document = () => {
return (
<MDXProvider>
<ParagraphDefinition />
<ParagraphDefinitionHTML />
</MDXProvider>
)
}
export default Document;
The MDXProvider
is expecting a components
prop. This will be an object that uses key-value pairs to map which markdown element should be styled by which UI component.
We'll import all UI components and set the components
object, accordingly.
// imports...
import Header1 from '../components/markdown-styles/Header1'
import Header3 from '../components/markdown-styles/Header3'
import Paragraph from '../components/markdown-styles/Paragraph'
import Link_ from '../components/markdown-styles/Link_'
import CodeBlock from '../components/markdown-styles/CodeBlock'
const components = {
h1: Header1,
h3: Header3,
p: Paragraph,
a: Link_,
pre: CodeBlock
}
const Document = () => {
return (
<MDXProvider components={components}>
<ParagraphDefinition />
<ParagraphDefinitionHTML />
</MDXProvider>
)
}
export default Document;
We now have a fully composed and styled markdown document! 🎉
5. Publish both React and MDX components to Bit
We'll start by installing Bit's CLI tool
$ npm install bit-bin --global
We'll then go to our project's root directory and initialize a Bit workspace.
$ cd mdx-gatsby-demo
$ bit init
We'll then tell Bit which components it should track. Here, we'll mark all components under each directory with the *
sign. We'll also add the --namespace
flag to organize each group of components according to its function (styling or content). This will determine how our soon-to-be-published components are tagged in Bit's component hub.
$ bit add src/components/content/* --namespace content
$ bit add src/components/markdown-styles/* --namespace markdown-styles
To compile our React components we’ll import and set a React compiler from Bit’s ENVs collection. These compilers are pre-configured. No need to worry about setting bundling plugins, etc.
$ bit import bit.envs/compilers/react --compiler
We'll "tag" all tracked components with the --all
flag. This will build, run tests (if there were any) and set a version to all components.
$ bit tag --all
To publish components, we'll first need to signup to a (free) Bit account and create a "component collection".
Once done, we can head back to our terminal, log in and publish.
$ bit login
$ bit export <username>.<collection-name>
We now have a component collection for future markdown compositions and styling! 🎉
When exploring The component collection on Bit you'll notice they can be filtered using the "namespace" filter. This is another way to make it easier to find what we need.
Top comments (1)
Awesome tutorial! Never new MDX existed. Thanks!