How to use markdown in pages in Gatsby
Tags: gatsby, markdown, graphql
Published: 2019-10-07 07:54:00

Most tutorials show how to create full pages with Gatsby's `createPages`, like for blogs. However, what if we don't want to create pages? What if we want to take markdown from markdown files and insert them into pages instead? That is, how do we insert markdown into JSX? I haven't found a lot of details on this. So, this is a fairly quick piece on how to do it.

In this article, we will display markdown from a markdown file in the default index.js landing page.

I kind of wrote this from memory. Please let me know if I made a mistake, missed anything, or if you have a faster method.

# Why put markdown in pages?

I work with non-tech people. Sometimes, we want an SSG instead of a CMS. Markdown is easy to learn and write with.

This lets content folks publish with ease. They can upload markdown files and edit them whenever they like.

# Basic setup

## Create a new project

Set up the default starter project with `gatsby new myproj`. You can read more about starting a project [here](https://www.gatsbyjs.org/docs/quick-start/).

## Install plugins

We need to install gatsby-source-filesystem to help Gatsby access the markdown files that we'll soon create. So, do this in your project root directory: `npm install gatsby-source-filesystem`.

Tell Gatsby about this new plugin by adding this to the gatsby-config.js file:

```
plugins: [
  {
    resolve: `gatsby-source-filesystem`,
    options: {
      name: `markdown-pages`,
      path: `${__dirname}/src/markdown-pages`,
    },
  },
]
```

Next, install gatsby-transformer-remark, which lets Gatsby use markdown properly: `npm install gatsby-transformer-remark`

Add it to gatsby-config.js:

```
plugins: [
  {
    resolve: `gatsby-source-filesystem`,
    options: {
      path: `${__dirname}/src/markdown-pages`,
      name: `markdown-pages`,
    },
  },
  `gatsby-transformer-remark`,
]
```

Note the `path`. It's `${__dirname}/src/markdown-pages`. This means Gatsby should look into /src/markdown-pages for markdown files. Create the markdown-pages directory in src.

## Make a markdown file

Create a markdown file in /src/markdown-pages. For our current demo purpose, let's create one called home.md.

Examples online usually tell us to create something like this:

```
---
path: "/"
date: "2019-10-06"
title: "About"
---

# About us

Here is the body of our content. It will be magically turned into HTML.
```

The part in `---` is the frontmatter. We place metadata in there.

# Graphql code

We'll make this really simple. We'll place our code in index.js so everything loads on the landing page. Find it in /src/pages/index.js.

We use graphql to look for the markdown file /src/markdown-pages/home.md. After checking out a handful of solutions, such as [here](https://github.com/gatsbyjs/gatsby/issues/9043) and [here](https://github.com/gatsbyjs/gatsby/issues/1634), I decided that the `allMarkdownRemark` method is probably easiest. Feel free to let me know if you have an even easier option.

I haven't figured out how to fully properly use regex in graphql yet but we'll use it as shown below. It should work for files named in simple ways.

Here's the query to get the file:


```
graphql`
query {
  allMarkdownRemark(
    filter: {fileAbsolutePath: {regex: "/home/"}}
  ) {
      ...
    }
}
`
```

In the code above, the regex bit looks for file names with "home" in it. You might want to tailor the regex to your needs. It's currently fine for me because I'm using it for a simple site with just Home, Contact, and About pages.

Here's how to get the markdown content in home.md:


```
graphql`
query {
  allMarkdownRemark(
    filter: {fileAbsolutePath: {regex: "/home/"}}
  ) {
      edges {
        node {
          frontmatter {
            title
            date(formatString: "DD MMMM YYYY")
          }
          html
        }
      }
    }
}
```

In the code above, we've extracted a couple of frontmatter metadata. We've left out `path` because it's not needed today. We've also taken the html content.

It's not done yet though. We have to export it. So, the whole code looks like this:

```
export const query = graphql`
query {
  allMarkdownRemark(
    filter: {fileAbsolutePath: {regex: "/home/"}}
  ) {
      edges {
        node {
          frontmatter {
            title
            date(formatString: "DD MMMM YYYY")
          }
          html
        }
      }
    }
}
`
```

Place it just above `export default IndexPage`.

# Query response is in props

The data from the graphql query will be in props. So, let's put it into `IndexPage` with `{ data }`:

```
const IndexPage = ({ data }) => (
  ...
)
```

Let's also pass into `IndexPage` a method we'll use to read and display the markdown properly. We'll call it `md()`.

To make things simpler, let's get rid of almost all the default JSX in `IndexPage` and just have `{md({ data })}` in it:

```
const IndexPage = ({ data }) => (
  <Layout>
    {md({ data })}
  </Layout >
)

```

Feel free to add other JSX to it if you like.

# Method to read markdown

Before we continue, let's note that the structure of the data follows the graphql query we made above. After some exploration, I found out that `allMarkdownRemark` returns an array. I then used both the graphql playground and console in developer tools to navigate the structure properly. Despite that, it still takes some experimentation to get right.

In the interest of time, I'll just tell you the markdown content we want is in `data.data.allMarkdownRemark.edges[0].node`.

Now, let's build the function `md()`. It has two important parts:

First, we destructure `frontmatter` and `html` from the props.

Second, we return the JSX we want with the markdown properly rendered.

Here's how it looks:

```
const md = (data) => {
  const { frontmatter, html } = data.data.allMarkdownRemark.edges[0].node

  return (<div>
    <h1>{frontmatter.title}</h1>
    <p>{frontmatter.date}</p>
    <div
      dangerouslySetInnerHTML={{ __html: html }}
    />
  </div>)
}
```

# The whole index.js

By now, our code should look like this:

```
import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"

const md = (data) => {
  const { frontmatter, html } = data.data.allMarkdownRemark.edges[0].node
  console.log(frontmatter.title)
  return (<div>
    <h1>{frontmatter.title}</h1>
    <p>{frontmatter.date}</p>
    <div
      dangerouslySetInnerHTML={{ __html: html }}
    />
  </div>)
}

const IndexPage = ({ data }) => (
  <Layout>
    {md({ data })}
  </Layout >
)

export const query = graphql`
query {
  allMarkdownRemark(
    filter: {fileAbsolutePath: {regex: "/home/"}}
  ) {
      edges {
        node {
          frontmatter {
            title
            date(formatString: "DD MMMM YYYY")
          }
          html
        }
      }
    }
}
`

export default IndexPage
```

Run `gatsby develop` and check out the page. It should be at localhost:8000.