Search
Michael Kingdom

Using Grommet with Gatsby

January 21, 2020

picture1

Gatsby is a popular, free, and open source framework based on ReactJS that helps developers quickly build websites and apps. Because Gatsby is a PWA (Progressive Web App) generator, it provides code and data splitting out-of-the-box. Gatsby loads only the critical HTML, CSS (cascading style sheets), data, and JavaScript required so websites load quickly. Gatsby uses a GraphQL query interface to easily get data from just about any source, making clicking around the website feel very fast. You can augment these capabilities and make great looking applications and websites mobile-friendly, accessible, and responsive by using Grommet. In this tutorial, I’ll show you how to get started using Grommet components and styles with Gatsby to make websites and applications more inviting.

Pre-requisites

This tutorial assumes you have Yarn as well as Node.js and npm installed.

Step 1: Create a basic Gatsby app

First, use npm to install the Gatsby commands and create a basic Gatsby app with the gatsby new <name> command. You can use an existing Gatsby starter (there are some that include Grommet), but we'll use the default Gatsby minimal app for this example.

npm install -g gatsby-cli
gatsby new gatsby-with-grommet 
cd gatsby-with-grommet

Step 2: Add in grommet dependencies

Add Grommet to the dependencies. We'll use Yarn, since Gatsby uses it when doing gatsby new.

yarn add grommet grommet-icons styled-components

Step 3: Start up a development server

Start up a Gatsby development server to make changes and see the effect of those changes in real time.

gatsby develop

Now, you can view the result in your local browser at http://localhost:8000/.

picture2

We aren't using Grommet components yet, so let's add some in, along with the Grommet themes.

Step 4: Start using Grommet components

First, replace the contents of the src/components/layout.css file with this simple bit of CSS to reset some browser defaults we don't want. We'll rely on Grommet's internal styles rather than use a separate CSS file to style the user interface (UI).

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

img {
  max-width: 100%;
  height: auto;
}

Next, make the main Layout component using the Grommet wrapper and theme, as well as the other equivalent Grommet components, instead of the literal html elements. Change src/components/layout.js to look like this:

import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"

import Header from "./header"
import "./layout.css"
import { Grommet, Anchor, Box, Footer, Text } from "grommet"
import { grommet } from "grommet/themes"

const Layout = ({ children }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  return (
    <Grommet
      theme={grommet}
      full
      style={{
        display: "flex",
        flexDirection: "column",
      }}
    >
      <Header siteTitle={data.site.siteMetadata.title} />
      <Box as="main" pad="medium" flex overflow="auto">
        {children}
      </Box>
      <Footer background="light-4" justify="center" pad="small">
        <Text textAlign="center" size="small">
          © {new Date().getFullYear()}, Built with
          {` `}
          <Anchor href="https://www.gatsbyjs.org">Gatsby</Anchor>
          {` and `}
          <Anchor href="https://v2.grommet.io">Grommet</Anchor>
        </Text>
      </Footer>
    </Grommet>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout

You’ll also want to change src/components/header.js to use the Grommet equivalents.

import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import { Header as GrommetHeader, Heading } from "grommet"

const Header = ({ siteTitle }) => (
  <GrommetHeader background="brand" justify="center">
    <Heading>
      <Link
        to="/"
        style={{
          color: `white`,
          textDecoration: `none`,
        }}
      >
        {siteTitle}
      </Link>
    </Heading>
  </GrommetHeader>
)

Header.propTypes = {
  siteTitle: PropTypes.string,
}

Header.defaultProps = {
  siteTitle: ``,
}

export default Header

Finally, change src/pages/index.js to use Grommet equivalents.

import React from "react"
import { Link } from "gatsby"
import { Box, Heading, Paragraph } from "grommet"

import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"

const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <Heading>Hi people</Heading>
    <Paragraph>Welcome to your new Gatsby site.</Paragraph>
    <Paragraph>Now go build something great.</Paragraph>
    <Box width={{ max: "300px" }} pad="small">
      <Image />
    </Box>
    <Link to="/page-2/">Go to page 2</Link>
  </Layout>
)

export default IndexPage

Make similar changes to src/pages/page-2.js.

Note that Gatsby has a way of optimizing and lazy-loading images that’s implemented in the example src/components/image.js. You can use something like this rather than Grommet's <Image> component to help optimize a Gatsby site.

You should now see the Grommet styling in the browser.

picture3

Step 5: Routing

Gatsby defines routes automatically for pages in the src/pages folder so many Gatsby applications don't have to set up routes or even interact with the router directly. Gatsby uses @reach/router instead of the react router. So, for efficient internal links, Gatsby applications use Gatsby's <Link> component. This component uses navigateTo from @reach/router to change routes. One way to get Grommet's styling for these internal links is to make a version of Grommet's <Anchor> that uses navigateTo.

Create a file in src/components called link.js that contains the following:

import React from "react"
import PropTypes from "prop-types"
import { Anchor } from "grommet"
import { navigate } from "gatsby"

const Link = ({ to, ...rest }) => (
  <Anchor
    href={to}
    onClick={ev => {
      navigate(to)
      ev.preventDefault()
    }}
    {...rest}
  />
)

Link.propTypes = {
  to: PropTypes.string,
}
export default Link

Now, change all the places that use Gatsby's <Link> to use this Link component instead. For example, change src/pages/index.js to import this new component and not the Gatsby Link component.

import React from "react"
// import { Link } from "gatsby"
import Link from "../components/link"
import { Box, Heading, Paragraph } from "grommet"

import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"

const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <Heading>Hi people</Heading>
    <Paragraph>Welcome to your new Gatsby site.</Paragraph>
    <Paragraph>Now go build something great.</Paragraph>
    <Box width={{ max: "300px" }} pad="small">
      <Image />
    </Box>
    <Link to="/page-2/">Go to page 2</Link>
  </Layout>
)

export default IndexPage

Because you started using this other Link, the Go to page 2 link on the main page is using the Grommet styling.

picture4

Make the same change to src/pages/page2.js and src/components/header.js to ensure those use the Grommet link styling as well.

Summary

You can see the complete result at https://github.com/MikeKingdom/gatsby-with-grommet-starter.

Gatsby is a great framework for making high-performing websites and web applications. Try adding Grommet to make these websites even better looking, responsive, accessible and mobile-friendly. If you have any questions, please join me on the Grommet Slack channel. You’ll find a lot of support there. And don’t forget to check out the HPE DEV site to learn more about all our platforms.

Related

Vinicius Monteiro

Coding styles: A personal preference or bad practice?

Oct 22, 2021
Didier Lalli

Calling all developers… Make your voices heard!

May 28, 2021
Joel Baxter & Kartik Mathur & Don Wake

Building Dynamic Machine Learning Pipelines with KubeDirector

Aug 14, 2020
Nicolas Perez

Apache Spark as a Distributed SQL Engine

Jan 7, 2021
Carol McDonald

Apache Spark Machine Learning Tutorial

Nov 25, 2020
Nicolas Perez

Apache Spark Packages, from XML to JSON

Dec 11, 2020
Dale Rensing

App DEV and the HPE Container Platform

Apr 9, 2020
Suzy Visvanathan

Best Practices for Migrating Your Apps to Containers and Kubernetes

Nov 25, 2020

HPE Developer Newsletter

Stay in the loop.

Sign up for the HPE Developer Newsletter or visit the Newsletter Archive to see past content.

By clicking on “Subscribe Now”, I agree to HPE sending me personalized email communication about HPE and select HPE-Partner products, services, offers and events. I understand that my email address will be used in accordance with HPE Privacy Statement. You may unsubscribe from receiving HPE and HPE-Partner news and offers at any time by clicking on the Unsubscribe button at the bottom of the newsletter.

For more information on how HPE manages, uses, and protects your personal data please refer to HPE Privacy Statement.