chrisg86
chrisg86

Reputation: 11907

Configure gatsby-transformer-remark to add default classes

I am using gatsby with plugins gatsby-source-filesystem and gatsby-transformer-remark to display markdown files as pages, as described in the official docs.

It works great, but I am looking for a way to add default classes to all the elements that are converted from markdown.

Let's say I want each <h1> element to have a class of title, and <h2> elements to have a class of subtitle by default.

I managed to do something like this with gatsby-remark-attr, but with that I can only add classes programmatically in the markdown file. It looks like this:

# My markdown heading
{.title}

## Subtitle
{.subtitle}

converts to

<h1 class="title">My markdown heading</h1>
<h2 class="subtitle">Subtitle</h2>

I am looking for a way to define the default classes once for each element and have them applied automatically, without having to specify them in the markdown files.

Upvotes: 5

Views: 1774

Answers (2)

Janosh
Janosh

Reputation: 4732

There's also gatsby-remark-classes (GitHub, NPM) which allows you to specify a classMap in your gatsby-config.js.

{
  resolve: `gatsby-transformer-remark`,
  options: {
    plugins: [
      {
        resolve: `gatsby-remark-classes`,
        options: {
          classMap: {
            "heading[depth=1]": "title",
            "heading[depth=2]": "subtitle",
            paragraph: "para",
          }
        }
      }
    ]
  }
}

Its functionality seems identical to gatsby-remark-default-html-attrs. Funnily enough, these two plugins were created within one day of each other (Feb 1, 2019 and Feb 2, 2019, respectively).

Upvotes: 1

Derek Nguyen
Derek Nguyen

Reputation: 11577

TL,DR: Use gatsby-remark-default-html-attrs


Gatsby's gatsby-transformer-remark use mdast-util-to-hast to convert markdown nodes to html nodes, which then stringified into raw HTML. If the markdown node has a data.hProperties object, it'll be converted into html attributes.

Let's say you want to add class name foo to all h1 nodes. You'd need to:

  • find the markdown node that'll eventually be transformed into a h1 html element
  • add className to its data.hProperties

0. Setup

First, you need a custom plugin to modify markdown nodes of transformer-remark. Thankfully, creating a local plugin with gatsby is trivial:

# Create a `plugins` folder at your root
mkdir plugins
mkdir plugins/remark-default-class-name
cd plugins/remark-default-class-name
npm init -y
touch index.js

You'll now get this structure:

root
  |--src
  |--gatsby-config.js
  `--plugins
      `--remark-default-class-name
           |--package.json
           `--index.js

Then add the new local plugin to gatsby-config.js:

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
  +       `remark-default-class-name`
        ],
      },
    },

1. Find the markdown node

The plugin will be given a markdownAST object, which allows you to find & modify nodes.

I'd use unist-util-select to help finding the right node. It comes with gatsby-transformer-remark, but if for some reasons it doesn't work, just install it again.

From here on, it's trivial to find the node:

const { selectAll } = require('unist-util-select');

module.exports = ({ markdownAST }) => {
  // `heading` is equivalent to `h1...h6` in markdown.
  // specify [depth] allow us to target the right heading tag.
  const h1Nodes = selectAll('heading[depth=1]', markdownAST);

  console.log(h1Nodes) 
  // this yields  
  // [{ type: "heading", children: [{ type: "text", value: "..." }] }, ...]
}

2. Add className to its data.hProperties

We can modify the node directly.

  const h1Nodes = selectAll('heading[depth=1]', markdownAST);

- console.log(h1Nodes)
  // node doesn't always have data
+ if (!node.data) node.data = {};
+ node.data.hProperties = {
+   className: 'foo'
+ }

That's it, all h1 should have a foo class now.

This is a particular interesting question for me, since I'm learning about Unist and its ecosystem, which powers remark; so thanks for that.

I make a simple plugin that's a bit more generic here, feel free to try it out & let me know if something failed.

Upvotes: 11

Related Questions