Reputation: 11907
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
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
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:
h1
html elementdata.hProperties
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`
],
},
},
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: "..." }] }, ...]
}
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