Adding a Loader Spinner in Gatsby site
Tags: gatsby
Published: 2020-06-17 08:13:48

Usually we don't need a loader spinner in our Gatsby site as Gatsby sites usually fast (Super blazing fast as Gatsby.org claims). But in some situations we need it. For example if our users have poor WiFi or or slow 2G/3G connections then it would be a good idea to have loader spinner before contents load. I tested my few Gatsby sites in Regular 3G, 4G and WIFI it super fast but when I tested in slow 2G or DSL it takes time. That's the reality. 

So I was wondering if I could show a some kind of loading spinner before the site or components are ready.

## html.js

This is the file where we will use to load our spinner.

First step: Type the following command in your terminal:

```
cp .cache/default-html.js src/html.js
```
It will copy the default-html.js file and rename it as html.js and will place it in our src directory.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dkhckp3ftmxx4ketpg3y.png)

If you open the html.js file you may see something like this: 

```
import React from "react"
import PropTypes from "prop-types"

export default function HTML(props) {
  return (
    <html {...props.htmlAttributes}>
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="x-ua-compatible" content="ie=edge" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        {props.headComponents}
      </head>
      <body {...props.bodyAttributes}>
        {props.preBodyComponents}
        <div
          key={`body`}
          id="___gatsby"
          dangerouslySetInnerHTML={{ __html: props.body }}
        />
        {props.postBodyComponents}
      </body>
    </html>
  )
}

HTML.propTypes = {
  htmlAttributes: PropTypes.object,
  headComponents: PropTypes.array,
  bodyAttributes: PropTypes.object,
  preBodyComponents: PropTypes.array,
  body: PropTypes.string,
  postBodyComponents: PropTypes.array,
}

```

Now we have to add our own image (either gif or SVG) and add few lines of css and regular javascript codes:

```
import LoaderSVG from './img/loader.svg'
```

```
<div
    key={`loader`}
              id="___loader"
              style={{
                alignItems: "center",
                backgroundColor: "#F2F2F2",
                display: "flex",
                justifyContent: "center",
                position: "absolute",
                left: 0,
                top: 0,
                right: 0,
                bottom: 0,
                zIndex: 100,
              }}
           >
              <img 
                src={LoaderSVG} 
                alt="loading spinner" 
                width="150" 
                height="150"
              />
        </div>
```

Complete code something like this: 

```
import React from "react"
import PropTypes from "prop-types"
import LoaderSVG from './img/loader.svg'

export default function HTML(props) {
  return (
    <html {...props.htmlAttributes}>
      <head>
        <meta charSet="utf-8" />
        <meta httpEquiv="x-ua-compatible" content="ie=edge" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        {props.headComponents}
      </head>
      <body {...props.bodyAttributes}>
        {props.preBodyComponents}
        <div
              key={`loader`}
              id="___loader"
              style={{
                alignItems: "center",
                backgroundColor: "#F2F2F2",
                display: "flex",
                justifyContent: "center",
                position: "absolute",
                left: 0,
                top: 0,
                right: 0,
                bottom: 0,
                zIndex: 100,
              }}
           >
           <img 
              src={LoaderSVG} 
              alt="loading spinner" 
              width="150" 
              height="150"
           />
        </div>
        <div
          key={`body`}
          id="___gatsby"
          dangerouslySetInnerHTML={{ __html: props.body }}
        />
        {props.postBodyComponents}
      </body>
    </html>
  )
}

HTML.propTypes = {
  htmlAttributes: PropTypes.object,
  headComponents: PropTypes.array,
  bodyAttributes: PropTypes.object,
  preBodyComponents: PropTypes.array,
  body: PropTypes.string,
  postBodyComponents: PropTypes.array,
}
```

Now we will add our JavaScript code in `gatsby-browser.js`. 

Add this following code: 

```
export const onInitialClientRender = () => {
    setTimeout(function() {
        document.getElementById("___loader").style.display = "none"
    }, 1000)
}
```
Save it. 

Now we can restart our Gatsby. And run the site. You may not notice the loader spinner if you have fast connection but if you can change your connection to DSL or slow 2G and refresh the browser then you will see the loader. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3k7ioft09ungezvdyfh3.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1rq82z7lksdv59n1tjvj.png)

Reference: 
* [https://www.gatsbyjs.org/docs/custom-html/](https://www.gatsbyjs.org/docs/custom-html/)
* [https://www.gatsbyjs.org/docs/browser-apis/#onInitialClientRender](https://www.gatsbyjs.org/docs/browser-apis/#onInitialClientRender)


Live site: 
[Nirvana](https://nirvana.netlify.app/)