Styling Gatsby Site

Styling is an integral part to static sites. While Gatsby allows us to get our sites up and running fast, it is best if we can style them efficiently and beautifully too.


Gatsby Sites

Overview (Gatsby sites)

  • Content centric, "content mesh" -> layout and styling is integral to information presentation
  • Gatsby sites are React sites, anything you have from React is on the table
  • Many beautifully styled starters, but we may want to customize

In short, we are facing a lot of content in different forms, we have many options on the table, and we want to customize them easily.

What we share today provides one way that works for me. It is definitely not the only way. But I have two goals

  • To get your hands dirty into styling your sites
  • To get you

Three layers of my styling of a content-focused site

To me, styling a Gatsby site boils down to the following three aspects:

  • Typesetting
  • Layout
  • Components

I'm going to show you how we can, with Gatsby and React, treat each of these aspects independently but make them work well with each other, without loss of consistency.


Typesetting has a historical root. It's actually about how printers (profession) used to set the content of a page when printing a book. So this is actually a transported concept. When I say typesetting a web page, I'm talking about defining fonts of texts, horizontal and vertical spacing, maximum widths, and relations to each other.


Layout dictates how the page is organized. It also takes care of how the whole page responds to different viewports.


Eventually all the content will be rendered onto the screen in building blocks of components. And the components for navbar is going to look differently than those for your article, sidebar, etc.

The components are styled rather individually but they should also fit the context.


(Demo with the mindset above)


There are a few reasons why we want to work on typography first (not just because we love choosing fonts).

  • The variables we touch, font-size, font-family, as well as spacing and vertical rhythm affect global styling, and we want them to
  • We set the HTML's root font-size that will be used as the base font size for rem values


We are going to use TypographyJS. This is a CSS-in-JS library that focuses on dealing with the site's typography. And it is created by Kyle Matthews, also the creator of Gatsby.

To use TypographyJS in Gatsby, first we need to add the library and its corresponding Gatsby plugin to our package:

$ yarn add gatsby-plugin-typography react-typography typography
# or
$ npm install --save gatsby-plugin-typography react-typography typography

Then, we'll need to specify in gatsby-config.js that we are using this library and the plugin, and we'll specify a file in which we'll write the typography related CSS in a JS object.

// gatsby-config.js
module.exports = {
  plugins: [
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`

We'll also need to create the typography.js file. Then, we'll need to restart the dev server. Nothing will change yet. Now let's work on the typography.js file.

// src/utils/typography.js
import T from "typography";

const typography = new T({
  baseFontSize: "18px",
  baseLineHeight: 1.7

export default typography;
  • instantiate a new typography instance from the typography class we import from typography,
  • with an option of baseFontSize and baseLineHeight
  • export default the instance
  • refresh the page and see the page changes

Typography provides a quick API to load google fonts. Let's pick a Google font.

// src/utils/typogrpahy.js
import T from "typography";

const typography = new T({
  // ...
  googleFonts: [
      name: "IBM Plex Mono",
      styles: ["700", "700i", "400", "400i"]
  headerFontFamily: ["IBM Plex Mono", "monospace"],
  bodyFontFamily: ["IBM Plex Mono", "monospace"]
  • go to
  • find IBM Plex Mono
  • TypographyJS provides a googleFonts field that is an array of object for the Google fonts that we need to lead
  • specify these fonts in headerFontFamily and bodyFontFamily
  • for both of these places, we want the fonts to fallback to monospace if the font file is missing

Next, we want to specify some more detailed adjustments to the typography, we're "typesetting" the page!!

The TypographyJS API has a special field called overrideStyles which is supposed to a function. If you initialize the typography object with this function provided, it will be called with a few util functions for you to use, and the objects you return in this function will be injected to your site.

// src/utils/typography.js
import T from "typography";

const typography = new T({
  overrideStyles: ({ rhythm, adjustFontSizeTo }) => {
    return {
      h1: {
        marginTop: rhythm(1.2),
        marginBottom: rhythm(1.2),
        lineHeight: 1.8,
        fontStyle: "italic"

The two util functions we are going to use are rhythm and adjustFontSizeTo.

rhythm stands for vertical rhythm. This is another library created (transported) by Kyle. You can read more about it in its separate repo.

What it does intuitively is that gives you 1 line of height. But why can't you just use, say, pixel numbers? This is because, the font sizes are different in headings and body texts. And sometimes you may adjust the line height as well, resulting yet another different final line height. So what rhythm gives you is the actual one line of height in the text's context. And we can use the number at margins, paddings, etc.

So in our h1, we want to give it more spacing before and after the heading, so we're gonna say that both marginTop and marginBottom will be 1.2 lines of height. We can do that by calling rhythm with the number 1.2.

And because the italic glyphs of IBM Plex Mono are really cute, let's use italics for h1 as well.

h2: {
  marginTop: rhythm(1.1),
  marginBottom: rhythm(1.1),
  lineHeight: 1.5,
h3: {
  marginTop: rhythm(1.03),
  marginBottom: rhythm(1.03),
  lineHeight: 1.3,
h4: {
  marginTop: rhythm(1),
  marginBottom: rhythm(1),
h5: {
  marginTop: rhythm(0.9),
  marginBottom: rhythm(0.9),
h6: {
  marginTop: rhythm(0.75),
  marginBottom: rhythm(0.75),

There are a few more headings and for today I'm going to cheat.

Next, we'll update the styles for the anchors because in our site the anchors are all black, hovering which gives a thicker underline. So similarly we can write for the a selector:

a: {
  color: 'black',
  textDecoration: 'none',
  borderBottom: '1.5px solid #222',
  paddingBottom: '2px',
  transition: 'all .1s ease',
  • explain the border bottom

Now we can see the changes to our anchors, but not yet the thickened border bottom on hover. We need to implement the CSS For 'a:hover'. In fact, TypographyJS allows us to simply put CSS selectors as strings in the object keys, so we can do:

'a:hover, a:active, a:focus': {
  borderBottom: '3px solid #222',

Extra styles in typography:

'h1 a, h2 a, h3 a': {
  borderBottom: '2px solid #222',
'h1 a:hover, h1 a:active, h2 a:hover, h2 a:active, h3 a:hover, h3 a:active': {
  borderBottom: '4px solid #222',
ul: {
  paddingInlineStart: '20px',
'ul li': {
  marginBottom: '8px',
code: {
  fontSize: '1.2em',
  fontFamily: "'IBM Plex Mono', monospace",

Before we move on to the next section, I'd like to point out that with TypographyJS you can actually write media queries exactly like how we put the relatively more complex selectors in the object key. And as a matter of fact, TypographyJS has a package that includes all the common media query strings.

But we're not going to use that part of the library because we'll move on to consider our site's layout separately.

And one last thing before we move away from Typography. The library contains a list of styles where you may use directly to your Gatsby site. You can even play around with it, tweak the numbers of the prepackaged styles to fit your own needs. Demo and full API docs at