Components
The MDX core library accepts a string and exports a JSX string. It uses a custom pragma which customizes the rendering of elements in Markdown and JSX.
Tranpilation
Consider the following MDX:
import MyComponent from './my-component'export const author = 'Fred Flintstone'# Title<MyComponent />Lorem ipsum dolor sit amet.
MDX core turns that text into roughly the following JSX to be consumed by your app:
import React from 'react'import MyComponent from './my-component'export const author = 'Fred Flintstone'const layoutProps = { author }export default MDXContent({ components, ...props }) => (<wrapper {...props} {...layoutProps}><h1>Title</h1><MyComponent /><p>Lorem ipsum dolor sit amet.</p></wrapper>)MDXContent.isMDXComponent = true
If the component mapping contains a p
key, that will be used for
Lorem ipsum dolor sit amet.
.
Otherwise a standard p
tag is rendered (<p>Lorem ipsum dolor sit amet.</p>
).
This is what allows you to pull in existing components to style your MDX
documents via the MDXProvider
Layout props
You’ll also notice that layoutProps
is created based on your exports
and then passed to the wrapper. This allows for the wrapper to use
those props automatically for handling things like adding an author
bio to the wrapped document.
isMDXComponent
If you need to check whether a React component has been created by MDX,
all MDX components have a static property isMDXComponent
:
import React from 'react'import ChangeLog from '../changelog.mdx'export default () => (<div><p>Component type: {ChangeLog.isMDXComponent ? 'MDX' : 'Regular'}</p><ChangeLog /></div>)
MDXProvider
Caveats
Because MDXProvider uses React Context directly, it is affected by the same caveats. It is therefore important that you do not declare your components mapping inline in the JSX. Doing so will trigger a rerender of your entire MDX page with every render cycle. Not only is this bad for performance, but it can cause unwanted side affects, like breaking in-page browser navigation.
Avoid this by following declaring your mapping as a constant.
Updating the mapping object during application runtime
If you need to change the mapping during runtime, declare it on the componentʼs state object:
import React from 'react'import { MDXProvider } from '@mdx-js/react'import { Heading, Text, Pre, Code, Table } from './components'export default class Layout extends React.Component {state = {h1: Heading.H1,h2: Heading.H2,// ...p: Text,code: Pre,inlineCode: Code}render() {return (<MDXProvider components={this.state}><main {...this.props} /></MDXProvider>)}}
You can now use the setState
function to update the mapping object and be assured that it wonʼt trigger unnecessary renders.