30

Obviously, that's not an easy task, as the only thing that changes in the html.js template file by default are the head meta tags and the content.

The meta tags are handled by the Helmet component ({head.title.toComponent()} and {head.meta.toComponent()}) and the HTML changes inside the template are managed by React. (<div id="react-mount" dangerouslySetInnerHTML={{ __html: this.props.body }} />)

The body tag however is outside the scope of React, which is why I can't figure out how to change it on-the-fly when I navigate from page to page. That's exactly what I'd need though as I wanna apply a different body background to each page.

I know that I could solve this by using the exports.onRouteUpdate in gatsby-browser.js, but I would like the class to be present even if JS is disabled in the browser. Means I'd like it to be there even if I export without the bundle.js file, just generating the static site HTML.

Marcel Kalveram
  • 1,295
  • 1
  • 14
  • 22

3 Answers3

72

React-helmet now supports adding attributes to body element as well.

So, if you want to add a class to a specific component/page, you can do something like this:

import Helmet from 'react-helmet'

// Inside your component
<Helmet
    bodyAttributes={{
        class: 'new-class-for-body'
    }}
/>

// or

<Helmet>
    <body className="new-class-for-body" />
</Helmet>
Nil
  • 174
  • 1
  • 3
  • 14
Moris
  • 2,903
  • 16
  • 15
  • Thank you! It did solved the issue in my case. I just had to `yarn upgrade react-helmet && yarn start` and then I saw the class applied to the body element. – LukyVj Sep 03 '19 at 10:39
8

February 2023:

Since the release of gatsby@5.5.0, the preferred way of doing this is using the Gatsby Head API. (The gatsby-plugin-react-helmet plugin has been deprecated.)

In your page file, export a <Head> component with a <body className /> element inside:

export const Head = () => <body className="your-class-name" />

You can also do this alongside other <Head> changes, e.g.:

export const Head = () => (
  <>
    <html lang="en" />
    <title>Hello World</title>
    <meta name="description" content="Hello World" />
    <body className="home-page" />
  </>
)
Justin Reese
  • 81
  • 1
  • 2
6

It does look like react-helmet supports dynamically/statically setting a class on the <html> element.

They don't want to support setting classes on the body though... https://github.com/nfl/react-helmet/issues/182

If you really need to support body classes, then this module does something very similar to react-helmet but for body classes https://github.com/iest/react-body-classname

Kyle Mathews
  • 3,240
  • 24
  • 22
  • 2
    This is at least not true anymore, you can add a class to the body with helmet via `bodyAttributes` – Dominic Dec 06 '18 at 20:48
  • Does facebook read metadata **dynamically** added with gatsby-helmet ? Or will I have to use SSR? e.g. a product details page will show different products all with their own metadata dynamically injected into tag – Haseeb Burki Dec 22 '18 at 16:56