reactjs – (Gatsby) How to pass image source as a prop in MDX component

I’m trying to create a Figure component in which I pass the img src along with other data.

I realize it’s not straightforward—eg, this thread—but I thought it would work fine with normal HTML img tags

The image is not displaying. Does that mean that this limitation also applies to HTML img tags within components?

If this is the case, I guess I indeed ought to use Gatsby’s dynamic images. How would I do this in a static query (nonpage component)? This thread had me believing it isn’t possible—or at least a hack?

The component inside MDX documents:

<Figure 
  image=""
  size=""
  caption=""
  credits=""
/>

Figure.js:

import * as React from "react"

const Figure = ({ image, size, caption, credits }) => {
  return (
    <figure className={size}>
      <img src={image} alt={caption} />
      <figcaption>
        <span>{caption}</span>
        <span>{credits}</span>
      </figcaption>
    </figure>
  )
}

export default Figure

articlePostTemplate.js

import * as React from "react"
import { graphql } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import Layout from "../components/layout.js"
import Seo from "../components/seo.js"

const PostTemplate = ({ data, location }) => {
  let post = data.mdx

  return (
    <Layout location={location}>
      <Seo
        title={post.frontmatter.title}
        description={post.frontmatter.lead}
        date={post.frontmatter.computerDate}
      />
      <article className="post">
        <header className="post" id="intro">
          <p className="date">
            <time dateTime={post.frontmatter.computerDate}>{post.frontmatter.humanDate}</time>
          </p>
          <h1 itemprop="headline">{post.frontmatter.title}</h1>
          <p className="lead">{post.frontmatter.lead}</p>
        </header>
        <section className="post" id="body-text">
          <MDXRenderer data={data}>{post.body}</MDXRenderer>
        </section>
      </article>
    </Layout>
  )
}

export default PostTemplate

export const pageQuery = graphql`
  query PostBySlug(
    $id: String!
  ) {
    site {
      siteMetadata {
        title
      }
    }
    mdx(id: { eq: $id }) {
      id
      excerpt(pruneLength: 160)
      body
      frontmatter {
        title
        computerDate: date(formatString: "YYYY-MM-DD")
        humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
        hook
        type
        lead
        featuredImage {
          childImageSharp {
            fluid(maxWidth: 800) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }
`

gatsby-config.js

module.exports = {
  …
  },
  plugins: [
    `gatsby-plugin-image`,
    `gatsby-plugin-sitemap`,
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [`.md`, `.mdx`],
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: `900000000000`,
              linkImagesToOriginal: false,
              backgroundColor: `none`,
            },
          },
          {
            resolve: `gatsby-remark-responsive-iframe`,
            options: {
              wrapperStyle: `margin-bottom: 1.07var(--line-length)`,
            },
          },
          `gatsby-remark-prismjs`,
          `gatsby-remark-copy-linked-files`,
          `gatsby-remark-smartypants`,
          {
            resolve: `gatsby-remark-autolink-headers`,
              options: {
                icon: false,
                itemprop: `heading`,
                maintainCase: false,
                removeAccents: true,
                elements: [`h2`, `h3`, `h4`],
              },
          }
        ],
      },
    },
    …
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/content/`,
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/data`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/pages/`,
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `journalistikk`,
        path: `${__dirname}/content/journalism/`,
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `discussion`,
        path: `${__dirname}/content/discussion/`,
      }
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `photography`,
        path: `${__dirname}/content/photography/`,
      }
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `Gatsby Starter Blog`,
        short_name: `GatsbyJS`,
        start_url: `/`,
        background_color: `#ffffff`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`,
      },
    },
    `gatsby-plugin-react-helmet`,
  ],
}

gatsby-node.js

const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions

  const articlePostTemplate = path.resolve(`./src/templates/articlePostTemplate.js`)

  const result = await graphql(
    `
      {
        allMdx(
          sort: { fields: [frontmatter___date], order: ASC }
          limit: 1000
        ) {
          nodes {
            id
            frontmatter {
              title
              computerDate: date(formatString: "YYYY-MM-DD")
              humanDate: date(formatString: "D. MMMM YYYY", locale: "nb")
            }
            fields {
              slug
            }
          }
        }
      }
    `
  )

  if (result.errors) {
    reporter.panicOnBuild(
      `There was an error loading your blog posts`,
      result.errors
    )
    return
  }

  const posts = result.data.allMdx.nodes

  if (posts.length > 0) {
    posts.forEach((post, index) => {
      [index + 1].id

      createPage({
        path: post.fields.slug,
        component: articlePostTemplate,
        context: {
          id: post.id
        },
      })
    })
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })

    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions

 
  createTypes(`
    type SiteSiteMetadata {
      author: Author
      siteUrl: String
      social: Social
    }

    type Author {
      name: String
      summary: String
    }

    type Social {
      twitter: String
      instagram: String
      mail: String
    }

    type MarkdownRemark implements Node {
      frontmatter: Frontmatter
      fields: Fields
    }

    type Frontmatter {
      title: String
      description:  String
      date: Date @dateformat
    }

    type Fields {
      slug: String
    }
  `)
}

layout.js

import * as React from "react"
import { MDXProvider } from "@mdx-js/react"
import { Link } from "gatsby"
import DWChart from "react-datawrapper-chart"
import Header from "./Header"
import Footer from "./Footer"
import Figure from "./Figure"

const shortcodes = { Link, DWChart, Figure }

export default function Layout({ children }) {
  return (
    <div className="layout-wrapper">
      <Header />
      <main>
        <MDXProvider components={shortcodes}>{children}</MDXProvider>
      </main>
      <Footer />
    </div>
  )
}

Leave a Comment