Search code examples
reactjsmarkdownreact-props

Passing component props to MDX Provider - ReactJS


Im using MDX Provider as shown below :-

      <MDXProvider components={components}>
        <ButtonMarkdown />
      </MDXProvider>

Components is :-

import { Button, Heading } from './components/button';

const components = {
  pre: (props: any) => <div {...props} />,
  h1: Heading,
  h2: Heading,
  h3: Heading,
  code: Codeblock,
  inlineCode: Codeblock,
};

However I want to be able to pass props into the Heading component being used in my markdown file eg :-

## Heading Two

should be changed to :-

<Heading level="2">Heading Two</Heading>

How would i do this to be able to ensure my markdown is being passed to correct props for the relevant component?


Solution

  • You can provide several levels of headings in the MDXProvider:

    <MDXProvider components={{
      h1: Heading1,
      h2: Heading2,
      h3: Heading3,
      h4: Heading4,
      pre: Code,
      table: Table,
      th: TableHeading,
      tr: TableRow,
      td: TableCell,
      p: Paragraph
    }}>
      {children}
    </MDXProvider>
    

    They could be defined like this:

    const Heading1: FC = ({ children }) => (
      <Heading level={1}>{children}</Heading>
    );
    
    const Heading2: FC = ({ children }) => (
      <Heading level={2}>{children}</Heading>
    );
    
    const Heading3: FC = ({ children }) => (
      <Heading level={3}>{children}</Heading>
    );
    
    const Heading4: FC = ({ children }) => (
      <Heading level={4}>{children}</Heading>
    );
    
    

    By the time the MDX renders, the second-level heading ## will end up being replaced by <Heading level={2}>.

    Just to make this answer more complete, this is one way to achieve a proper Heading component that will render <h1> when level prop is 1 and so on:

    export const Heading: FC = ({
      level = 1,
      children,
    }) => {
      const HeadingElement = `h${level}`;
      return (
        <HeadingElement>
          {children}
        </HeadingElement>
      );
    };