70 %
Chris Biscardi

Towards Shortcodes for Gatsby Sites

Many blogging platforms have the concept of shortcodes. This is especially prevalent in the WordPress community and other places like Hugo use them too.

WordPress' look like square brackets with content inside them.

[recent-posts]

but what if we need to configure them?

[recent-posts posts="5"]

or if we want to have some content that the shortcode uses to display. We'll call it "children".

[recent-posts posts="5"]Posts Heading[/recent-posts]

In all their variations across platforms, there's a bit of syntax marking the start of a shortcode, the attributes a shortcode might accept, and the children of the shortcode.

Shortcodes and Gatsby

Gatsby is built on React and if we look at the three previous examples we can see that React has solved this syntax in an open and ubiquitous way via JSX.

JS
<RecentPosts />
<RecentPosts posts={5} />
<RecentPosts posts={5}>Posts Heading</RecentPosts>

It would be great if we could not only re-use this syntax, but also re-use the entire React ecosystem as a set of shortcodes.

Well... we can.

Gatsby and MDX

MDX allows us to put React components inside Markdown content. As an example, if we wanted to render color picker (or a visualization of some data, etc) we could do the following:

import { SketchPicker } from 'react-color'
# Hello, world!
Here's a color picker!
<SketchPicker />

Which is great! We get our color picker rendered on the page in a very similar way to the shortcodes from WordPress or Hugo. There's still one problem though, the import. Shortcodes from other ecosystems don't need to be imported.

Introducing globalScope

So in a recent commit to gatsby-mdx I introduced a new configuration option called globalScope. This configuration option lets us specify a set of components that are then made available to any MDX content we render on our Gatsby site.

It works like this. In your gatsby config simple use a code string that imports some components and then exports an object of all of the components with the names you want to use for your shortcodes.

JS
module.exports = {
plugins: [
{
resolve: `gatsby-mdx`,
options: {
globalScope: `import { SketchPicker } from 'react-color';
export default { Picker: SketchPicker }`
}
}
]
};

and now this exact markdown content will render your shortcode, no import required.

md
# A non-page
In not the pages directory, with nothing special about it
<Picker/>

You can check out the color picker example on the gatsby-mdx kitchen sink site.

What next

Well, this can be applied to Youtube videos, Twitter oembeds, or anything else really. These components can even use any data in the page context, embed a StaticQuery, and they can execute completely arbitrary code because the shortcodes are now React components. The world is your oyster (it's not my oyster because I don't like oysters. That's why you get the oysters)

<ProgressBar percent="80" />
<Youtube id="dQw4w9WgXcQ" />
<Gist gistId="72ef76ecc6ef2c5d58780bac9174d3d1" />