Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDXRenderer: components available globally as shortcodes not working #22257

Closed
apolopena opened this issue Mar 13, 2020 · 5 comments
Closed

MDXRenderer: components available globally as shortcodes not working #22257

apolopena opened this issue Mar 13, 2020 · 5 comments
Labels
type: bug An issue or pull request relating to a bug in Gatsby

Comments

@apolopena
Copy link
Contributor

apolopena commented Mar 13, 2020

Description

I am trying to get JSX components to work globally in my markdown files for my blog as per the documentation: Importing and Using Components in MDX

The proper html is not being rendered from my custom component inthe markdown, Rather I get a plain

tag with the attributes set in the custom component.

When I import my custom component into a .mdx file in src/pages and import the component from within the .md file as per import-components-for-use-from-another-library the proper html is rendered:

  <blockquote class='sc-bdVaJa jKmSoD'>
    <p>
      <small>
        This is a foobar<cite>by some genius</cite>
      </small>
    </p>
  </blockquote>

I have simplified my test to putting a <MDXRenderer> right in the blog.js file which resides in src/pages to rule out any issues with pathing and createPages in gatsby-node.js
The contents of my blog.js is:

import Bio from "../components/bio"
import Layout from "../components/layout"
import SEO from "../components/seo"
import { rhythm } from "../utils/typography"
import Button from "../components/button"

import { MDXRenderer } from "gatsby-plugin-mdx"
import { ImgCaption } from "../components/ImgCaption"

class Blog extends React.Component {
  render() {
    const { data } = this.props
    const siteTitle = data.site.siteMetadata.title
    const posts = data.allMdx.edges

    const shortcodes = { ImgCaption }

    return (
      <Layout location={this.props.location} title={siteTitle}>
        <SEO title="All posts" />
        <Bio />
        <div style={{ margin: "40px 0 40px" }}>
          {posts.map(({ node }) => {
            const title = node.frontmatter.title || node.fields.slug
            return (
              <React.Fragment>
                <div key={node.fields.slug} style={{paddingLeft: '15px'}}>
                <MDXRenderer
                components={shortcodes}    
                >
                  {node.body}
                </MDXRenderer>
                  <h3
                    style={{
                      marginBottom: rhythm(1 / 8),
                    }}
                  >
                    <Link
                      style={{ boxShadow: `none` }}
                      to={`blog${node.fields.slug}`}
                    >
                      {title}
                    </Link>
                  </h3>
                  <small>{node.frontmatter.date}</small>
                  <p
                    style={{
                      marginBottom: rhythm(1 / 2),
                      marginTop: rhythm(1 / 4)
                    }}
                    dangerouslySetInnerHTML={{
                      __html: node.frontmatter.description || node.excerpt,
                    }}
                  /> 
              </div>
              <hr style={{borderTop: '1px solid #bbb', margin: '0 0 15px'}} />
              </React.Fragment>
            )
          })}
        </div>
        <Link to="/">
          <Button marginTop="85px">Go Home</Button>
        </Link>
      </Layout>
    )
  }
}

export default Blog

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allMdx(sort: { fields: [frontmatter___date], order: DESC } filter: {fileAbsolutePath: {regex: "/content/blog/"}}) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            title
            description
          }
          body
        }
      }
    }
  }
`

My custom component is here: src/components/ImgCaption.js
and looks like this:

import React from 'react'
import styled from 'styled-components'
import colors from '../../content/assets/style/colors.scss'

export const ImgCaption = ({description, citation}) => {
  return (
    <Container>
      <p>
        <small>
          {description} 
          <cite>
            {citation}
          </cite>
        </small>
      </p>
    </Container>
  )
}

const Container = styled.blockquote`
  border-left: 1px solid ${colors.charm_pink};
  padding-left: .35em !important;
  p {
    small {
      font-size: 65%;
      cite {
        font-size: xx-small;
      }
    }
  }
`

My gatsby-config.js looks like this:

module.exports = {
  siteMetadata: {
    // edit below
    title: `blah`,
    author: `blah bah`,
    description: `blah blah blah blah blah`,
    siteUrl: `https://blah.com/`,
    social: {
      twitter: `blahblah`,
    },
  },
  plugins: [
    {
      resolve:`gatsby-source-filesystem`, // this entry has to be the first or will not work as per FAQ 
      options:{
        path:`${__dirname}/static/assets`,
        name:`assets`
      }
    },
    `gatsby-plugin-sass`,
    `gatsby-plugin-netlify-cms`,
    `gatsby-plugin-styled-components`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    `gatsby-plugin-offline`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-feed-mdx`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/blog`,
        name: `blog`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/data`,
        name: `content`,
      },
    },
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [".mdx", ".md"],
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590,
            },
          },
          {
            resolve: "gatsby-remark-external-links",
            options: {
              target: "_blank",
              rel: "nofollow"
            }
          },
          {
            resolve: `gatsby-remark-responsive-iframe`,
            options: {
              wrapperStyle: `margin-bottom: 1.0725rem`,
            },
          },
          {
            resolve: `gatsby-remark-vscode`,
          },
          {
            resolve: `gatsby-remark-copy-linked-files`,
          },
          {
            resolve: `gatsby-remark-smartypants`,
          },
        ],
      },
    },
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        // edit below
        // trackingId: `ADD YOUR TRACKING ID HERE`,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `blah`,
        short_name: `blah`,
        start_url: `/`,
        background_color: `#ffffff`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        // edit below
        icon: `content/assets/gatsby-icon.png`,
      },
    },
    /*{
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`,
      },
    },*/
  ],
}

Steps to reproduce

  • Place a file named test.md in /content/assets/blog
  • Ensure that test.md contains the following content:
---
path: 03-10-20-1
date: 2020-13-10T16:51:48.059Z
title: this is a test
description: 'testing a possible bug'
---
This is regular content
<ImgCaption description='This is a foobar' citation='by some genius' />
This is more regular content

Expected result

The following html should be rendered from the custom component:

  <blockquote class='sc-bdVaJa jKmSoD'>
    <p>
      <small>
        This is a foobar<cite>by some genius</cite>
      </small>
    </p>
  </blockquote>

Actual result

The following html is rendered for the html component:

<div description="This is a foobar" citation="by some genius"></div>

Environment

System:
OS: Windows 10 10.0.18362
CPU: (8) x64 Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
Binaries:
Node: 12.4.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.19.1 - ~\AppData\Roaming\npm\yarn.CMD
npm: 6.13.2 - C:\Program Files\nodejs\npm.CMD
Languages:
Python: 2.7.16 - /c/Python27/python
Browsers:
Edge: 44.18362.449.0
npmPackages:
gatsby: ^2.3.25 => 2.19.34
gatsby-image: ^2.0.39 => 2.2.43
gatsby-plugin-feed-mdx: ^1.0.0 => 1.0.1
gatsby-plugin-google-analytics: ^2.0.18 => 2.1.37
gatsby-plugin-manifest: ^2.0.29 => 2.2.45
gatsby-plugin-mdx: ^1.0.52 => 1.0.78
gatsby-plugin-netlify-cms: ^4.0.0 => 4.1.41
gatsby-plugin-offline: ^2.0.25 => 2.2.10
gatsby-plugin-react-helmet: ^3.0.12 => 3.1.23
gatsby-plugin-sass: ^2.1.30 => 2.1.30
gatsby-plugin-sharp: ^2.0.35 => 2.4.8
gatsby-plugin-styled-components: ^3.0.7 => 3.1.20
gatsby-plugin-typography: ^2.2.13 => 2.3.24
gatsby-remark-copy-linked-files: ^2.0.11 => 2.1.39
gatsby-remark-external-links: ^0.0.4 => 0.0.4
gatsby-remark-images: ^2.0.6 => 2.0.6
gatsby-remark-responsive-iframe: ^2.1.1 => 2.2.33
gatsby-remark-smartypants: ^2.0.9 => 2.1.22
gatsby-remark-vscode: ^1.0.4 => 1.4.0
gatsby-source-filesystem: ^2.0.29 => 2.1.51
gatsby-transformer-sharp: ^2.1.18 => 2.3.17

@apolopena apolopena added the type: bug An issue or pull request relating to a bug in Gatsby label Mar 13, 2020
@flikteoh
Copy link

I believe the correct place for your custom components to work is to put them into MDXProvider, @apolopena

https://mdxjs.com/blog/shortcodes

@lukePeavey
Copy link
Contributor

To expand on @flikteoh's comment...

In your code, you are passing your components to MDXRenderer. Instead, you should pass custom component to MDXProvider.

From the docs:

All MDX components passed into the components prop of the MDXProvider will be made available to MDX documents that are nested under the provider.

// src/components/layout.js

import React from "react"
import { MDXProvider } from "@mdx-js/react"
import { Chart, Pullquote, Message } from "./ui"

const shortcodes = { Chart, Pullquote, Message }

export default ({ children }) => (
  <MDXProvider components={shortcodes}>{children}</MDXProvider>
)

The MDXProvider in this example is in a layout component that wraps all MDX pages, you can read about this pattern in the layout section of the gatsby-plugin-mdx README.

You can specify the default layout component for different types of mdx pages in the plugin options.

// in gatsby-config.js

plugins: [
  {
    resolve: `gatsby-plugin-mdx`,
    options: {
      defaultLayouts: {
        default: require.resolve("./src/components/layout.js"),
        posts: require.resolve("./src/components/posts-layout.js"),
      },
    },
  },
]

@LekoArts
Copy link
Contributor

Thank you for opening this!

As others have said you'll need to use MDXProvider to provide the shortcodes. The confusing behavior of MDXRenderer accepting this in the first place is tracked here: #21682

We're marking this issue as answered and closing it for now but please feel free to comment here if you would like to continue this discussion. We also recommend heading over to our communities if you have questions that are not bug reports or feature requests. We hope we managed to help and thank you for using Gatsby!

@apolopena
Copy link
Contributor Author

Thanks to all of you. Turns out I did not read the docs properly. It is useful to see #21682

@JSinkler713
Copy link
Contributor

JSinkler713 commented Apr 28, 2021

Looks like everyone here gets it, but I'll just post this for the next soul trying to use it with MDXRenderer. You want your MDXProvider to wrap your MDXRenderer. Then you will have access to all your components

import React from "react"
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { MDXProvider } from "@mdx-js/react"
import { Chart, Pullquote, Message } from "./ui"

const shortcodes = { Chart, Pullquote, Message }

export default ({ children }) => (
  <MDXProvider components={shortcodes}>
    <MDXRenderer>{children}</MDXRenderer>
  </MDXProvider>
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

No branches or pull requests

5 participants