Skip to content

Create a Custom Image Component with Mdx and GraphQL

Trang Le edited this page Dec 15, 2020 · 1 revision

Creating a custom image component with Mdx allows you to selectively style images in a way that is not possible with Markdown, such as:

  • float or align image
  • apply special effects like drop shadow to make an image stands out, or filter to overlay text
  • add caption

Create an image component

This component will

  • query all images in the filesystem with static query
  • loop through the list of images, and check for the first image whose originalName field value is equal to the src in the prop.
  • if this image exists, nest it inside a <figure> tag, which is in turn enclosed by a <div> element.
// src/components/CaptionedImage.js
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"
import styles from "./CaptionedImage.module.scss"

export default function CaptionedImage({ path, alt }) {
  const { allImageSharp } = useStaticQuery(graphql`
    query {
      allImageSharp {
        edges {
          node {
            fluid(maxWidth: 900) {
              ...GatsbyImageSharpFluid
              originalName
            }
          }
        }
      }
    }
  `)
  const image = allImageSharp.edges.find(
    edge => edge.node.fluid.originalName === path
  )
  if (!image) return null
  return (
    <div className={styles.imageBlock}>
      <figure class={styles.figure}>
        <Img className={styles.image} fluid={image.node.fluid} alt={alt} />
      </figure>
    </div>
  )
}

Reference the image component in a mdx file

// content/blog/<Name of the directory>/index.md

---
title: "Example"
---
import CaptionedImage from "../../../src/components/CaptionedImage

<p>According to research by Kissmetrics, photo captions are read 300% more times than the actual article copy.
<CaptionedImage path="dancing-otter.jpq" alt="dancing otter" />

Add caption to the image

It is a waste to include a sparkling photo without a caption. Let's add a <figcaption> that renders the caption.

//...
if (!image) return null
  return (
    <div className={styles.imageBlock}>
      <figure class={styles.figure}>
        <Img className={styles.image} fluid={image.node.fluid} alt={alt} />
        <figcaption
          className={styles.caption}
          dangerouslySetInnerHTML={{ __html: caption }}
        ></figcaption>
      </figure>
    </div>
  )

Then, in the mdx files that import the image component above, add a caption prop.

// content/blog/<Name of the directory>/index.md

---
title: "Example"
---
import CaptionedImage from "../../../src/components/CaptionedImage

<p>According to research by Kissmetrics, photo captions are read 300% more times than the actual article copy.
<CaptionedImage path="dancing-otter.jpq" alt="dancing otter" caption='<span>Photo by <a href="https://unsplash.com/@scienceinhd?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Science in HD</a> on <a href="https://unsplash.com/s/photos/server?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
</span>' />

Final look

Image with Caption Generated from a Custom React Component