Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure gatsby-transformer-remark to add default classes

Tags:

gatsby

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.

like image 553
chrisg86 Avatar asked Feb 01 '19 12:02

chrisg86


2 Answers

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.

like image 183
Derek Nguyen Avatar answered Oct 18 '22 13:10

Derek Nguyen


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).

like image 22
Casimir Avatar answered Oct 18 '22 15:10

Casimir