How to use Gatsby's Head API with MDX
Hi there! Iām excited, are you? Of course you are!
In Gatsby 4.19.0 the team shipped the Gatsby Head API š
But what does this mean for you, and why am I excited?
React Helmet
Historically the way to add indexable meta data to you Gatsby siteās <head>
element was to use a combination of
react-helmet
and gatsby-plugin-react-helmet
, but rather worryingly,
react-helmet hasnāt really been updated since 2020. š¬
What does it mean for you?
Using an Open-source library thatās not been well maintained can lead to headaches, as Iām sure youāre well aware.
Why Am I excited?
The Gatsby Engineering team recognizes this and have now moved all of that lovely Helmet functionality into the core framework! ā Superb!
Migration Options
To use the Head API today, upgrade to at least 4.19.0
and Iāll now talk you through the steps required to migrate from
react-helmet
to the Head API. Thereās two slightly different ways you might wish to approach this depending on if
youāre using unique pages or template/layout file. (MDX Blog posts with frontmatter
for example)
Iāve prepared an example repo and x2 PRās which you can use for reference.
Example Repo (Using React Helmet)
PRās (Using The Head API)
- āļø feat/use-head-api-fs-routes
- āļø feat/use-head-api-gatsby-node
Getting Started
Iāve tried to consider the most common scenario based on the approaches I see many folks use. Your use case may well be different.
Remove React Helmet
npm uninstall react-helmet gatsby-plugin-react-helmet
// gatsby-config.js
module.exports = {
...
plugins: [
- 'gatsby-plugin-react-helmet',
...
]
};
Page
Generally I see folks using an <Seo />
component somewhere in a page or page template file. In the example repo please
have a look at
src/pages/index.js#L9, and
hereās a similar looking code snippet.
Seo
// src/pages/index.js
import React, { Fragment } from 'react';
import Seo from '../components/seo';
const Page = () => {
return (
<Fragment>
<Seo title='Gatsby Head API MDX' />
<main>...</main>
</Fragment>
);
};
export default Page;
ā¦ and hereās what the same page looks like using the Head API
export const Head
// src/pages/index.js
import React, { Fragment } from 'react';
import Seo from '../components/seo';
const Page = () => {
return (
<Fragment>
- <Seo title="Gatsby Head API MDX" />
<main>...</main>
</Fragment>
);
};
export default Page;
+ export const Head = () => {
+ return <Seo title="Gatsby Head API MDX" />;
+ };
Seo component
Now you can remove any reference to <Helmet />
from the <Seo />
component.
// src/components/seo.js
import React from 'react';
- import { Helmet } from 'react-helmet';
const Seo = ({ title }) => {
return (
- <Helmet>
<title>{title}</title>
- </Helmet>
);
};
export default Seo;
ā¦ and thatās it!
Frontmatter as title
The above example shows a simple method for āhard-codingā a title and passing it on to the <Seo />
component via the
title
prop. In Page templates youāll likely need to use the title
as defined in the frontmatter
. Take a look at
the src from the example repo:
src/pages/posts/{mdx.frontmatter__title}.js#L43
Head props
Before you get going, you might like to inspect the props
passed to the Head API. They should be the same as whatās
passed to the page, E.g.
export const Head = (props) => {
console.log(JSON.stringify(props, null, 2));
return null;
};
In my example repo this results in something similar to the below.
{
"location": {
"pathname": "/posts/this-is-post-one"
},
"params": {},
"data": {
"mdx": {
"frontmatter": {
"title": "This is post one"
},
"body": "..."
}
},
"pageContext": {
"id": "6aa907b2-4040-5e38-b6f0-4f1762068476"
}
}
The bit Iām most interested in is data.mdx.frontmatter.title
as this is what Iāll need to pass on to the <Seo />
component to display in the HTML <title />
.
export const Head = ({
data: {
mdx: {
frontmatter: { title },
},
},
}) => {
return <Seo title={title} />;
};
Now when I visit each of the post pages in the browser I see the page title change in my browser tab, and when inspect
the DOM I see the following. Notice: the data attribute on the title. If it says data-gatsby-head
youāre all set!
// http://www.mywebsite.com/post-one
<head>
<title data-gatsby-head="true">This is post one</title>
</head>
ā¦ and thatās it, for real this time!
A short read if you're hacking on your @GatsbyJS site this weekend.
— Paul Scanlon (@PaulieScanlon) July 29, 2022
Remove react-helmet, and use the new Head API āļøhttps://t.co/kDxVedPAS1