ホーム > Gatsby > How to Display Thumbnails in Markdown Posts in Gatsby.js
Gatsby

How to Display Thumbnails in Markdown Posts in Gatsby.js

Thank you for your continued support.
This article contains advertisements that help fund our operations.

⇨ Table of contents for React articles is here

This article summarizes how to set up thumbnails for posts written in Markdown in Gatsby.js.

Introduction

There are two methods introduced here.

One is a simple method of placing an image and specifying its absolute path, and the other is a method using GraphQL to compress and optimize the image.

Also, note that the plugin for images has changed from gatsby-image to gatsby-plugin-image, and the way you write the code will vary depending on the plugin used.

Simple Method to Set Thumbnails

Required Plugin

You may already have it installed, but you need the following plugin:

npm install gatsby-source-filesystem

Where to Place Images

Place images under the /static/ directory.

For example, place the image at /static/images/sample.png.

Check gatsby-config.js

Depending on your project setup, the following entry may or may not be present. If it is present, you're good to go. If not, add it to the plugins:[] array in the module.exports.

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `media`,
        path: `${__dirname}/static`,
      },
    },

Add to gatsby-node.js

Add a string for the thumbnail's absolute path to the schema's Frontmatter.

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(
    //~~~snip
    `
    type Frontmatter {
      title: String,
      thumbnail: String, //← Add this
    }
  `
  )
  //~~~snip
}

Write the Thumbnail Path in the Markdown

---
title: How to display thumbnails in Gatsby
thumbnail: "/images/sample.png"
---

Call It in the GraphQL Query of the Page

export const query = graphql`
  query PostBySlug($slug: String!) {
    post: markdownRemark(
      fields: { slug: { eq: $slug }}
    ) {
      id
      html
      frontmatter {
        title
        thumbnail // ← Add this to frontmatter
      }
    }
  }
`

Display the Image

<img src="{edge.node.frontmatter.thumbnail}" />

That's the simple method.

Method Using GraphQL to Compress and Optimize the Image

Install Required Plugins

npm install gatsby-plugin-image gatsby-transformer-sharp gatsby-plugin-sharp gatsby-source-filesystem

Where to Place the File

This time, you can't specify the absolute path, so place the image in a directory that is easy to reference with a relative path from the Markdown file.

├── content
│    ├── blog
     │    └── slug
     │         └── ja.md //記事ファイル
     └── thumbnail
           └── sample.png

The relative path from the article file is ../../thumbnail/sample.png.

Add to gatsby-config.js

Add the following three items to the plugins:[] array in the module.exports.

Be careful as some of the same content may already be written.

    `gatsby-plugin-image`,
    `gatsby-transformer-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `thumbnail`,
        path: `${__dirname}/content/thumbnail`,
      },
    },

Add to gatsby-node.js Frontmatter

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  createTypes(
    //~~~snip
    `
    type Frontmatter {
      title: String,
      thumbnail: File @fileByRelativePath,
    }
  `
  )
  //~~~snip
}

This outputs the File type, and @fileByRelativePath allows you to specify the relative path.

Check GraphQL

Go to http://localhost:8000/___graphql and confirm that thumbnail in Frontmatter outputs several fields.

Retrieve Data in the Page

Now that you know many fields are output, you will use the gatsbyImageData field to display an optimized image.

export const pageQuery = graphql`
  {
    allMarkdownRemark() {
      edges {
        node {
          frontmatter {
            title
            thumbnail {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    }
  }
`

Display the Thumbnail Image

Use GatsbyImage from gatsby-plugin-image to display the image.

import { GatsbyImage } from "gatsby-plugin-image"

const Posts = ({ data }) => {
  const edges = data.allMarkdownRemark.edges
  return (
    <div>
      {edges.map(edge => (
        <GatsbyImage
          image={
            edge.node.frontmatter.thumbnail?.childImageSharp.gatsbyImageData
          }
          alt=""
          height="140"
        />
      ))}
    </div>
  )
}

export default Posts

export const pageQuery = graphql`
  {
    allMarkdownRemark() {
      edges {
        node {
          frontmatter {
            title
            thumbnail {
              childImageSharp {
                gatsbyImageData
              }
            }
          }
        }
      }
    }
  }
`

Gatsby Image plugin

Check the Output

Here's what the output looks like in HTML.

<picture>
  <source
    type="image/avif"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/5e601/react.avif  320w,
      /static/638be90904f9f9248d3c69cb2992c562/14473/react.avif  640w,
      /static/638be90904f9f9248d3c69cb2992c562/1f487/react.avif 1280w
    "
    sizes="(min-width: 1280px) 1280px, 100vw" />
  <source
    type="image/webp"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/a0615/react.webp  320w,
      /static/638be90904f9f9248d3c69cb2992c562/6789b/react.webp  640w,
      /static/638be90904f9f9248d3c69cb2992c562/3602f/react.webp 1280w
    "
    sizes="(min-width: 1280px) 1280px, 100vw" />
  <img
    height="905"
    width="1280"
    src="/static/638be90904f9f9248d3c69cb2992c562/eed66/react.png"
    alt=""
    loading="lazy"
    decoding="async"
    sizes="(min-width: 1280px) 1280px, 100vw"
    srcset="
      /static/638be90904f9f9248d3c69cb2992c562/aaddb/react.png  320w,
      /static/638be90904f9f9248d3c69cb2992c562/94304/react.png  640w,
      /static/638be90904f9f9248d3c69cb2992c562/eed66/react.png 1280w
    "
/></picture>

You can also pass className as props to easily style with CSS.

<GatsbyImage
  className="object-cover h-36 hover:opacity-70 duration-200"
  image={edge.node.frontmatter.socialImage?.childImageSharp.gatsbyImageData}
  alt=""
  height="140"
/>

How to Use gatsby-plugin-images

If Using the Old gatsby-image

GraphQL Query Changes

In the older version, you would retrieve the fluid data to display images.

export const pageQuery = graphql`
  query {
    allMarkdownRemark() {
      nodes {
        frontmatter {
          title
          thumbnail {
            childImageSharp {
              fluid(maxWidth: 1280) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
      }
    }
  }
`

How to Display

The props will now use fluid.

import Image from "gatsby-image"

const BlogIndex = ({ data, location }) => {
  const posts = data.allMarkdownRemark.nodes
  return (
    <div>
      {posts.map(post => {
        const thumbnail = post.frontmatter.thumbnail?.childImageSharp.fluid
        return (
          <div>
            <Image fluid={thumbnail} alt="" />
          </div>
        )
      })}
    </div>
  )
}

export default BlogIndex

Conclusion

That's all.

I hope this helps someone.

Please Provide Feedback
We would appreciate your feedback on this article. Feel free to leave a comment on any relevant YouTube video or reach out through the contact form. Thank you!