GSD

How to Build Flexible Landing Pages with Gatsby and ButterCMS

Posted by Isaac Okoro on October 10, 2023

Landing pages are standalone web pages made especially for marketing or advertising efforts. They are the pages that visitors "land" on after clicking on an email link, an advertisement from Google, a Twitter link, or any other comparable website. Landing pages can also be Search Engine Results Pages (SERPs), depending on your search. This article will cover how to build and add landing pages to a Gatsby application. We will be fetching most of the data for our landing page from a headless CMSButterCMS to be precise. 

Why use Gatsby?

There are lots of reasons for using Gatsby to create your applications. Some of them include performance, quality web experiences, speed, and different pre-rendering techniques.

Gatsby is an open-source static site generator (SSG) that uses GraphQL and Webpack as well as the front-end development framework React. It is used to create static web pages that adhere to the most recent web standards, are progressive web applications (PWA), and are speed- and security-optimized.

The Jamstack architecture, which combines JavaScript, APIs, and HTML without requiring a database or server-side programming language, powers Gatsby websites. With faster load times and simpler hosting and development, it is possible for Gatsby sites to be hosted by various means, such as through a content delivery network (CDN) or object storage service.

Performance is another priority when creating Gatsby websites. The end-user experience is significantly enhanced by pre-rendering pages as it decreases the requirement for servers to produce pages.

Why use ButterCMS?

ButterCMS is an amazing content management system built for a headless architecture. It is easy to use, comes with a nice component approach, and has great performance. The ButterCMS API is quick, straightforward, and simple to integrate into any application of your choice. Additionally, they offer SDKs for numerous programming languages. Butter stores multimedia materials on a low-latency CDN.

A headless CMS also offloads a lot of our work, freeing us up to concentrate on business needs. For instance, we may rely on the dashboard to give content editors a strong tool. The ability for editors to schedule content publication is a cool tool and makes ButterCMS a pleasure to work with. You can compose your content in advance and trust ButterCMS for publishing whenever you want. Additionally, we can configure roles and users by using the ButterCMS admin interface.

banner-cta-gatsby-border.webp

Tutorial: Creating landing pages with Gatsby and ButterCMS

We will be creating a landing page together from scratch in this section with Gatsby and TailwindCSS. We will put all the data in the application from the start and later we will transfer the data to ButterCMS and then fetch it from there. We will be working with TailwindCSS as it is a CSS framework built with utility in mind. It is low-level, extremely adaptable, and provides all the building blocks required to create custom designs without requiring you to struggle to override obnoxiously opinionated styles. Below is a preview of what we will be building: 

Rendered landing page

Prerequisites

The following requirements are needed to follow along in this tutorial:

  • Good grasp of JavaScript, Gatsby, React components, and hooks
  • An understanding of APIs and how to fetch data from them 
  • How content management systems (CMSs) work
  • CSS and how TailwindCSS works
  • A ButterCMS account
  • The Gatsby CLI installed
  • Node.js installed
  • Axios installed 

Let's get started!!

Bootstrap your Gatsby app

Before creating a new Gatsby application, you need to make sure that you have the Gatsby CLI installed on your system. You can see how to get it from here. Once you have that installed, go ahead and run the command below on your terminal to create a new Gatsby app:

npm init gatsby

Answer the questions from the prompts and in no time you will have your created project.

Answer the questions from Gatsby to create your project

The image above shows what you should see on your terminal after creating a Gatsby project. Next, navigate to the project folder and open it in the code editor of your choice.

navigate to the project folder and open it in the code editor

Installing TailwindCSS

Let’s learn how to install and use TailwindCSS in our Gatsby application. First, we run the command below to install Tailwind and its peer dependencies:

npm install -D tailwindcss postcss autoprefixer gatsby-plugin-postcssnpx 
tailwindcss init -p

The next thing we need to do is to enable the Gatsby PostCSS plugin. In the gatsby-config.js file, enable the gatsby-plugin-postcss:

// gatsby.config.js
module.exports = {
  plugins: [
    'gatsby-plugin-postcss',
    // ...
  ],
}

Next, add the paths to the Tailwind template files in the tailwind.config.js file:

// tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/pages/**/*.{js,jsx,ts,tsx}",
    "./src/components/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Create a styles/global.css file in the src folder and add the @tailwind directives.

@tailwind base;
@tailwind components;
@tailwind utilities;

Next, create a gatsby-browser.js file at the root of your project and import the created styles/global.css file into it:

import './src/styles/global.css'

And with that, we are done installing TailwindCSS in our project.

Setting up ButterCMS

With Tailwind installed, let's set up our ButterCMS project and create the data that we will be using in our application. To start, we need to create a ButterCMS account, which we can do by clicking on the link here. Your dashboard should look like the image below after creating a ButterCMS account.

ButterCMS account dashboard home page

Next, we will create an API key that will enable us to make requests to and fetch data from ButterCMS. Go to your account and click on settings.

ButterCMS account settings location

The image above shows where to get your API key. The next step is to copy your API key and keep it safe as we will be using it for fetching data. 

Read API token in your settings

With that done, let's install ButterCMS into our Gatsby project by running the command below:

npm install buttercms --save

Next, navigate to the gatsby-config.js file, copy the code below, and paste it in there.

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
  siteMetadata: {
    title: `butter and gatsby`,
    siteUrl: `https://www.yourdomain.tld`,
  },
  plugins: [
    'gatsby-plugin-postcss',
    {
      resolve: `gatsby-source-buttercms`,
      options: {
        authToken: process.env.BUTTER_CMS_API_KEY,
      },
    },
  ],
};

We are resolving our ButterCMS plugin in the code block above. We are also pointing to the .env file that we will create to hold the API key that we got from ButterCMS. Create a .env.development file at the root of the folder and paste your API key into it. It should look like the image below:

API key in the .env.development file

Building our components

We will be building out the components of our application. As we build out the components, we will immediately import them into the src/pages/index.js file so that we can see them in the browser. Let's get started.

The Navigation component

Create another folder inside the src folder and name it the components folder. Inside the components folder, create a Navigation.js file and paste the code below into it:

import * as React from "react";
import { Link } from "gatsby";

const Navigation = () => {
  return (
    <div className="navigationPanel flex bg-zinc-800 justify-between px-4 pr-1 py-2 items-center text-white sm:pr-5">
      <h1 className="text-3xl italic text-green-400">KenIs Technologies</h1>
      <nav className="lg:w-1/4 hidden md:block md:w-1/3">
        <ul className="flex justify-between px-5">
          <li className="hover:underline hover:scale-105 transition-all duration-200">
            <Link to="/">Home</Link>
          </li>
          <li className="hover:underline hover:scale-105 transition-all duration-200">
            <Link to="/about">About</Link>
          </li>
          <li className="hover:underline hover:scale-105 transition-all duration-200">
            <Link to="/contact">Contact</Link>
          </li>
        </ul>
      </nav>

      <button className="shopNowButton text-white bg-emerald-500 py-3 px-2 rounded-2xl text-lg md:bg-green-400 md:text-black hover:scale-105 transition-all duration-300">
        Shop Now
      </button>
    </div>
  );
};



export default Navigation;

The code above is for the navbar section of our application. The code above will look like the image below:

Rendered header

The Welcome component

Create a Welcome.js file in the components folder and paste the code below into it:

import * as React from "react";

const Welcome = () => {
  return (
    <div className="welcomePanel flex flex-col justify-center items-center bg-slate-800 h-2/3 text-white">
      <h2 className="text-4xl mb-5 text-green-400">
        Welcome to KenIs technologies
      </h2>
      <p className="text-xl w-3/4 md:w-1/2 text-center mb-5">
        We are a software development company, that deal in all kind of tech
        gadgets, from LED monitors to customizable photochromic lens to protect
        your eyes during screentime.Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam
        assumenda aliquid magni laudantium consectetur ut eius tenetur sequi
        velit voluptate!
      </p>

      <div className="flex pt-8">
        <button className="bg-green-400 py-3 px-2 rounded-xl text-black mr-5 text-lg hover:text-red">
          Shop Now
        </button>
 
        <button className="bg-green-400 py-3 px-2 rounded-xl text-black text-lg">
          Dream it
        </button>
      </div>
    </div>
  );
};

export default Welcome;

The code above is responsible for the welcome part of our application which looks something like the image below:

Rendered welcome component

The Items components

This component will be in charge of displaying the services and products of our company. Create an Items.js file in the components folder and paste the code below into it:

import * as React from "react";
import pic1 from "../images/gadget1.jpeg";
import pic2 from "../images/gadget2.jpeg";
import pic3 from "../images/gadget3.jpeg";
import pic4 from "../images/gadget4.jpeg";
import pic5 from "../images/gadget5.jpeg";
import pic6 from "../images/gadget6.jpeg";

const Items = () => {
  const blogs = [
    {
      title: "Smartphones",
      body: "Lorem ipsum...",
      author: "Kene",
      id: 1,
      imgSrc: pic1,
    },
    {
      title: "Rock your World!",
      body: "Lorem ipsum...",
      author: "Isaac",
      id: 2,
      imgSrc: pic2,
    },
    {
      title: "Laptops",
      body: "Lorem ipsum...",
      author: "Kene",
      id: 3,
      imgSrc: pic3,
    },
    {
      title: "Hard drives and hard disks",
      body: "Lorem ipsum...",
      author: "Kene",
      id: 4,
      imgSrc: pic4,
    },
    {
      title: "Game dev tools",
      body: "Lorem ipsum...",
      author: "Kene",
      id: 5,
      imgSrc: pic5,
    },
    {
      title: "Macbooks",
      body: "Lorem ipsum...",
      author: "Kene",
      id: 6,
      imgSrc: pic6,
    },
  ];

  return (
    <div className="flex px-8 bg-amber-50 py-24 flex-col">
      <h1 className="flex justify-center uppercase text-4xl text-green-600 pb-8 font-bold">
        Our products
      </h1>

      <div className="items-container w-full flex flex-wrap justify-center lg:w-full xl:w-3/4 xl:m-auto">
        {blogs.map((blog) => (
          <div
            className="px-1 bg-amber-100 m-5 pt-5 pb-10 w-96 flex flex-col items-center rounded-md hover:bg-yellow-100 hover:shadow-sm hover:-translate-y-1 transition-all duration-300"
            key={blog.id}
          >
            <img className="self-stretch" src={blog.imgSrc} />
            <h2 className="text-xl text-green-600 uppercase m-2 font-bold">
              {blog.title}
            </h2>
            <p className="text-lg italic">Written by {blog.author} </p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Items;

The code above is responsible for creating the image below:

Rendered items collection

The Features component

This will be the component that will hold some unique features of the company. Create a Features.js file in the folder component and paste the code below into it:

import * as React from "react";
import icon from "../images/banknote.svg";

const Features = () => {
  const feats = [
    {
      id: 1,
      imgSrc: icon,
      description: "Multiple Payment Options",
    },
    {
      id: 2,
      imgSrc: icon,
      description: "24/7 Customer Service",
    },
    {
      id: 3,
      imgSrc: icon,
      description: "Extensive product Information",
    },
    {
      id: 4,
      imgSrc: icon,
      description: "User reviews on all our products",
    },
    { id: 5, imgSrc: icon, description: "Secure Details" },
    {
      id: 6,
      imgSrc: icon,
      description: "Product filtering and sorting",
    },
  ];

  return (
    <div className="py-24">
      <h1 className="flex justify-center uppercase text-4xl text-green-600 pb-8 font-bold">
        Our main features
      </h1>

      <div className="w-full flex flex-wrap justify-center">
        {feats.map((feat) => (
          <div className="px-1 bg-amber-50 m-5 mb-8 pt-5 pb-10 w-96 flex flex-col items-center rounded-md hover:bg-amber-100 hover:-translate-y-1 transition-all duration-300">
            <img className="mb-5" src={feat.imgSrc} />
            <h2 className="text-lg italic">{feat.description}</h2>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Features;

The code above will render the image below on the browser

Rendered features component

The Extra component

This section will showcase some other services our company offers and which we want to include in our landing page.

import * as React from "react";
import pic1 from "../images/gadget1.jpeg";
import pic2 from "../images/gadget5.jpeg";
import pic3 from "../images/gadget6.jpeg";

const Extra = () => {
  const offers = [
    {
      title: "Software engineering internships",
      body: "We offer Internships to students who are registered with us and complete our training programme and pass with flying colours",
      id: 1,
      imgSrc: pic1,
    },
    {
      title: "Mentorship programmes",
      body: "As a techie, you may often be confused, need some professional guidance or perhaps someone to teach you about the real-world dev life. Enroll in our mentorship programme today!",
      id: 2,
      imgSrc: pic2,
    },
    {
      title: "Councelling",
      body: "We offer career and mental to anyone who needs it for no cost at all. E no easy to live for Naija, and we understand. Book a councelling session now!",
      author: "Kene",
      id: 3,
      imgSrc: pic3,
    },
  ];

  return (
    <div className="flex px-8 bg-amber-50 py-24 flex-col">
      <h1 className="flex justify-center uppercase text-4xl text-green-600 pb-8 font-bold">
        More from us
      </h1>

      <div className="items-container w-full flex flex-wrap justify-center">
        {offers.map((offer) => (
          <div
            className="px-0 bg-amber-100 m-5 pt-0 pb-10 w-96 flex flex-col items-center rounded-lg overflow-hidden hover:bg-amber-200 hover:-translate-y-1 transition-all duration-300"
            key={offer.id}
          >
            <img className="self-stretch" src={offer.imgSrc} />
            <h2 className="text-xl text-green-600 uppercase m-2 font-bold text-center">
              {offer.title}
            </h2>
            <p className="text-lg italic px-3 text-center mt-3">
              {offer.body}{" "}
            </p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Extra;

The code above will render the image below on the browser:

Rendered extra component

Create the Welcome component in ButterCMS

Navigate to the ButterCMS dashboard and then go to components:

Navigate to ButterCMS components

Delete the default components created by ButterCMS and let's create our first component which will be the Welcome component. Click on the New Content Type button and select Component from the drop-down menu as shown in the image below:

Select the New Content Type button and then select component from the drop down menu

 Add the following fields:

  • Short text as Header
  • Long text as Description

Header content fields configuration in buttercms

Click on Create Component at the top of the page and add the name you want for the component.

Name welcome component and add Meta data

Next, navigate to the Pages tab.

Navigate to the Pages tab

Click on New Page, then click on  Create New Page. Click on Component, and then click Add from Library. 

Configure a new page for the landing page

Select the newly created Welcome component and then proceed to save the Page Metadata.

Name landing page home page and give it meta data

Next, fill in the fields with the same data from the Welcome component that we created in our Gatsby application.

Add content to the welcome component

Click on the Publish button to save the changes. Now, let's test the API which we will be making our requests to.

API explorer for welcome component in buttercms

When we click on API Explorer, we can see the results posted and how we can make a fetch request to it.

api explorer json response for welcome component

Now, all we need to do is navigate to our code editor and make a request for the data. Let's do so in the Welcome.js file which will be covered in the next section. 

banner-cta-gatsby-border.webp

Fetching the components from ButterCMS

This section will cover how to fetch the created component from ButterCMS into our Gatsby application. Copy the code below and update the Welcome.js file.

import * as React from 'react';
import axios from 'axios';
const URL = `https://api.buttercms.com/v2/pages/*/home-page?auth_token=${process.env.BUTTER_CMS_API_KEY}`;
const Welcome = () => {
  
  const [data, setData] = React.useState(null);
  React.useEffect(() => {
    axios.get(URL)
      .then(res => console.log(res?.data?.data?.fields?.welcome_component))
      .catch(err => console.log(err));
  }, []);

  return (
    <div className="welcomePanel flex flex-col justify-center items-center bg-slate-800 h-2/3 text-white">
      // This stays the same 
    </div>
  );
};
export default Welcome;

We installed and imported axios to make our request. Next, we defined the URL to which we will be making our requests and then created a way to handle our state. We made a request to the defined URL and then logged the results to the console.

log results for welcome component into the console

Now, all we need to do is just pass the data to be rendered on the page.

import * as React from 'react';
import axios from 'axios';
const URL = `https://api.buttercms.com/v2/pages/*/home-page?auth_token=${process.env.BUTTER_CMS_API_KEY}`;
const Welcome = () => {
  
  const [data, setData] = React.useState(null);
  React.useEffect(() => {
    axios.get(URL)
      .then(res => setData(res?.data?.data?.fields?.welcome_component))
      .catch(err => console.log(err));
  }, []);

  return (
    <div className="welcomePanel flex flex-col justify-center items-center bg-slate-800 h-2/3 text-white">
      <h2 className="text-4xl mb-5 text-green-400">
        {data?.header}
      </h2>
      <p className="text-xl w-3/4 md:w-1/2 text-center mb-5">
        {data?.description}
      </p>
      <div className="flex pt-8">
        <button className="bg-green-400 py-3 px-2 rounded-xl text-black mr-5 text-lg hover:text-red">
          Shop Now
        </button>
        <button className="bg-green-400 py-3 px-2 rounded-xl text-black text-lg">
          Dream it
        </button>
      </div>
    </div>
  );
};
export default Welcome;

With that done, we have successfully fetched and rendered our data from ButterCMS.

Creating and fetching the Features, Items, and Extra collections

Since we are mapping through and displaying data in the Features.js, Items.js, and Extra.js files, we will be making use of the collections part of ButterCMS. You can find out more about why you will want to use ButterCMS collections here.

Navigate to the Collections tab in the side menu and click on New Item. We will begin with the Extra collection that will hold our different services.

Configure extra component

Configure your collection to have the following fields:

  • Media as Image
  • Number as Id
  • Short text as Title
  • Long text as body

Next, save the collection's name.

Name collection "Extra"

Create and configure the following collections by following the steps discussed earlier.

Configure your Item collection to have the following fields:

  • Media as Image
  • Number as Id
  • Short text as Title
  • Long text as body
  • Short text as author

Finally, configure your Features collection to have the following fields:

  • Media as Icon
  • Number as Id
  • Long text as description

Now go to the Collections section, select New Item, pick Extra from the drop-down menu, and fill in the data for the Extra collection.

Add content to extra collection item

Do the same for as many entries as you have in the Extra.js file. Click on the Publish button when done and then click on API Explorer to see the data and how to fetch it.

extra component api explorer json response

Now, go to the Extra.js file.

import * as React from "react";
import axios from "axios";
const URL = `https://api.buttercms.com/v2/content/extra?auth_token=${process.env.BUTTER_CMS_API_KEY}`;
const Extra = () => {
  const [datas, setDatas] = React.useState([]);
  React.useEffect(() => {
    axios.get(URL).then((res) => {
      console.log(res?.data?.data?.extra);
    });
  }, []);
  return (
    <div className="flex px-8 bg-amber-50 py-24 flex-col">
      // This stays the same 
    </div>
  );
};
export default Extra;

We defined the URL for our request and created our state.  Next, we made a request to the URL and then logged the result to the console.

made a request to the URL and then logged the result to the console

Now, pass the data to be rendered.

import * as React from "react";
import axios from "axios";
const URL = `https://api.buttercms.com/v2/content/extra?auth_token=${process.env.BUTTER_CMS_API_KEY}`;
const Extra = () => {
  const [datas, setDatas] = React.useState([]);
  React.useEffect(() => {
    axios.get(URL).then((res) => {
      setDatas(res?.data?.data?.extra);
    });
  }, []);
  return (
    <div className="flex px-8 bg-amber-50 py-24 flex-col">
      <h1 className="flex justify-center uppercase text-4xl text-green-600 pb-8 font-bold">
        More from us
      </h1>
      <div className="items-container w-full flex flex-wrap justify-center">
        {datas.map((data) => (
          <div
            className="px-0 bg-amber-100 m-5 pt-0 pb-10 w-96 flex flex-col items-center rounded-lg overflow-hidden hover:bg-amber-200 hover:-translate-y-1 transition-all duration-300"
            key={data.id}
          >
            <img className="self-stretch" src={data.imgSrc} alt='' />
            <h2 className="text-xl text-green-600 uppercase m-2 font-bold text-center">
              {data.title}
            </h2>
            <p className="text-lg italic px-3 text-center mt-3">
              {data.body}
            </p>
          </div>
        ))}
      </div>
    </div>
  );
};
export default Extra;

With that done, we see that the component is still rendering as it should. Now, follow the steps above for creating and fetching the Features and Items collections from ButterCMS.

With our progress so far, we should be able to achieve the results below.

Welcome component:

Rendered welcome component

Item component:

Rendered Item component

Feature component:

Rendered Feature component

Extra component:

Rendered extra component

Closing thoughts

This tutorial covered how to create a landing page with Gatsby and TailwindCSS and how to connect it to ButterCMS, which is an amazing content management system with great performance. We learned how to use ButterCMS pages, components, and collections. We also learned how to manage our page content from ButterCMS. 

Changing or updating content on your page is as easy as updating the collection item that is referenced in ButterCMS. We used Gatsby in this tutorial because it is a static site generator that comes with benefits such as speed, SEO, security, accessibility, and extensibility. It is also easy to pick up if you already have knowledge of React.  You can also take this further by adding some other components like hero images or values which you offer to your landing page. Congratulations on making it to this point and here is a link to the source code for this tutorial on Github.

Make sure you receive the freshest Butter product updates and Gatsby tutorials.
    
Isaac Okoro

Isaac is a software engineer and technical writer based in Nigeria. He is an avid reader and football lover with a passion for community and self-improvement.

ButterCMS is the #1 rated Headless CMS

G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award G2 crowd review award

Don’t miss a single post

Get our latest articles, stay updated!