Awesome Open Source
Awesome Open Source

Material UI MDX Example

This is an simple example for custom styled MDX.

We will integrate MDX with following modules:

Eventually, it's aim to render the markdown source to this.

Guide

Initial React App

Execute following command to create a React app:

npx create-react-app my-app
cd my-app

Install MDX

Execute following command to install mdx.macro:

yarn add mdx.macro

Then create the following src/App.js:

// src/App.js
import React, { lazy, Suspense } from 'react';
import { importMDX } from 'mdx.macro';

const Content = lazy(() => importMDX('./Content.mdx'));

const App = () => (
  <div>
    <Suspense fallback={<div>Loading...</div>}>
      <Content />
    </Suspense>
  </div>
);

export default App;

And then create the following src/Content.mdx:

# Hello, world!

🔗 Reference: Getting Started - Create React App

Setup Material UI

Install Material UI:

yarn add -D @material-ui/[email protected]

Add CSS Baseline:

  import React, { lazy, Suspense } from 'react';
  import { importMDX } from 'mdx.macro';
+ import CssBaseline from '@material-ui/core/CssBaseline';

  const Content = lazy(() => importMDX('./Content.mdx'));

  const App = () => (
-   <div>
-     <Suspense fallback={<div>Loading...</div>}>
-       <Content />
-     </Suspense>
-   </div>
+   <>
+     <CssBaseline />
+     <div>
+       <Suspense fallback={<div>Loading...</div>}>
+         <Content />
+       </Suspense>
+     </div>
+   </>
  );

  export default App;

Add Roboto Font into public/index.html:

      <title>React App</title>
+     <link
+       rel="stylesheet"
+       href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"
+     />
    </head>

Initial MDX Provider

Import MDXProvider:

  import React, { lazy, Suspense } from 'react';
  import { importMDX } from 'mdx.macro';
  import CssBaseline from '@material-ui/core/CssBaseline';
+ import { MDXProvider } from '@mdx-js/tag';
+ import components from './components';

  const Content = lazy(() => importMDX('./Content.mdx'));

  const App = () => (
    <>
      <CssBaseline />
-     <div>
-       <Suspense fallback={<div>Loading...</div>}>
-         <Content />
-       </Suspense>
-     </div>
+     <MDXProvider components={components}>
+       <div>
+         <Suspense fallback={<div>Loading...</div>}>
+           <Content />
+         </Suspense>
+       </div>
+     </MDXProvider>
    </>
  );

  export default App;

Notice: if you are using mdx-loader, you might have to use @mdx-js/react instead.

Set components:

// src/components.js
import React, { memo } from 'react';
import Typography from '@material-ui/core/Typography';

const components = {
  h1: (() => {
    const H1 = props => <Typography {...props} component="h1" variant="h1" />;
    return memo(H1);
  })(),
};

export default components;

You can see that your contents with MDX are applied Material UI components now.

Try to customize all components. You can check the table of components to know the tags to change.

You can also customize the wrapper. It's great to add a class name to handle the gutter between components like markdown.css inspired from github-markdown-css.

You can use the markdown-it demo code to preview the result.

Syntax Highlighted

You can use prism-react-renderer directly:

yarn add prism-react-renderer

Create a CodeBlock component:

// src/CodeBlock.js
import React from 'react';
import Highlight, { defaultProps } from 'prism-react-renderer';
export default ({ children, className }) => {
  const language = className.replace(/language-/, '');
  return (
    <Highlight {...defaultProps} code={children} language={language}>
      {({ className, style, tokens, getLineProps, getTokenProps }) => (
        <pre className={className} style={{ ...style, padding: '20px' }}>
          {tokens.map((line, i) => (
            <div key={i} {...getLineProps({ line, key: i })}>
              {line.map((token, key) => (
                <span key={key} {...getTokenProps({ token, key })} />
              ))}
            </div>
          ))}
        </pre>
      )}
    </Highlight>
  );
};

Add CodeBlock to MDXProvider:

  import React, { memo } from 'react';
  import Typography from '@material-ui/core/Typography';
+ import CodeBlock from './CodeBlock';

  const components = {
    h1: (() => {
      const H1 = props => <Typography {...props} component="h1" variant="h1" />;
      return memo(H1);
    })(),
+   code: CodeBlock,
  };

  export default components;

You can use syntax highlighted code block now!

  • Pros: easy
  • Cons: Prism components are not split

You can customized your own CodeBlock with code splitting like this. It will load only main prism at start and load other components only if they are required. The code would be highlighted after the required prism components loaded.

Summary

You can check the completed components here.


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Javascript (1,513,161
Reactjs (72,819
Markdown (6,628
Material Ui (3,499
Jsx (1,261
Mdx (431
Prism (205
Related Projects