loading...
Cover image for MDX Markdown Components: How to Use and Reuse

MDX Markdown Components: How to Use and Reuse

giteden profile image Eden Ella ・5 min read

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:

  1. Create a Gatsby blog site and set it up to use MDX

  2. Write a few MDX markdown files (components)

  3. Build a few React components for our markdown styling

  4. Compose everything together into a single document

  5. 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.

Posted on by:

giteden profile

Eden Ella

@giteden

Web developer. Open source lover.

Discussion

pic
Editor guide
 

Awesome tutorial! Never new MDX existed. Thanks!