GSD

How to Build Flexible Ecommerce Landing Pages with ButterCMS and Next.js

Posted by Marvel Ken on September 11, 2023

First impressions are crucial. They could make or break an entire business, determine if you make it to the next round of interviews, or dictate whether or not a new product grows to dominate a given industry. And in the digital sphere, it's often your landing pages that deliver this first impression, especially if operating an e-commerce brand.

So, in this tutorial, we will cover how to build a slick e-commerce landing page with ButterCMS and Next.js. Showing you how simple it can be to create unique landing pages that help move your prospects along your sales funnel rather than turning them away entirely. 

Why use Next.js?

Your team is sure to enjoy Next.js' many features because it was created with developers in mind. This includes the use of reusable components that help save time and money. Additional main advantages for developers include:

Developer experience

Developers may construct completely interactive, incredibly dynamic, and highly performant modern online applications using Next.js. Routing, data collecting, integrations, and static generation are all prevalent problems that Next.js addresses.

Better image optimization

Since version 10.0, Next.js has included an integrated image optimization feature that is an extension of the HTML element and has been updated for the modern web. Images are automatically optimized by Next.js's image component. The most recent standard, WebP, is used to serve and reduce the size of images. Graphics are also configured to benefit from smaller viewports.

See how Butter's simple content api works with your next.js app

Data security

Next.js provides a secure means of communicating with external APIs where sensitive information like API keys are not reflected on the client side. That is thanks to “API routes” which allow us to create server-side endpoints accessible from the frontend of our application. This comes with a few benefits which include:

  • Keeping sensitive information like private API routes and API keys on the server side and not on the browser. This prevents attackers from obtaining this information from the browser and prevents unauthorized access.
  • Having more control over how the application communicates with external APIs and services.

Speed

Next.js websites are speedy due to their static nature. Building a minimum viable product (MVP) is also considerably faster with Next because there are so many ready-to-use components available. By using components to build an MVP, you can quickly build and launch your website/product and immediately collect feedback from actual customers and make the necessary improvements to your product without wasting time or money.

Built-in CSS and TypeScript support

Next.js comes with built-in CSS and TypeScript support which allows developers to use these languages in our application without having to install or set up additional plugins or configurations.

With TypeScript enabled, we can write our code in .ts and .tsx files which gives us many of the benefits of TypeScript, including but not limited to:

  • Static typing which improves code quality and maintainability and helps catch errors at compile time rather than during runtime. 
  • High scalability which makes it great for large projects and codebases.
  • Support for modern JavaScript syntax and features which can also be compiled to a version of JavaScript that can run on older browsers.
  • A better development experience, and with VS Code and other modern text editors, TypeScript helps with code readability due to the IntelliSense feature.

Why use ButterCMS?

In any digital marketing plan, landing pages are essential tools. They are often used to target different audiences with different personalized versions of the same page. In cases where you need to create, publish, iterate, and re-iterate these pages on a regular basis, ButterCMS comes in handy. ButterCMS helps you build and manage your landing pages (and a plethora of other content types) seamlessly.

ButterCMS is a headless CMS that is widely used by enterprises and individuals to build their websites. Users with little to no technical coding expertise can easily create and manage their application’s content with ButterCMS after proper setup. 

With ButterCMS, you can easily write, publish, and manage your content using a variety of features such as components, collections, page types, and a built-in, ready-to-go blog engine. 

Tutorial overview: Building a flexible Next.js e-commerce landing page

For this tutorial, we will set up a content structure on ButterCMS that contains all the data to be displayed on the landing page. We will be building a landing page for a sneaker company. The contents to be included on the landing page are:

  • A home section that contains a hero image, hero text, navigation menu, and logo.
  • A services section showcasing cards containing offered services.
  • A products section where the company’s top merchandise, a description, and a price tag are shown.
  • A testimonials section.

After setting up the app content structure on ButterCMS, we will build and style the landing page using the Next.js framework and TailwindCSS library, while connecting our application to our CMS to display its content. Without further ado, let’s dive in and begin developing our application.

Tutorial prerequisites

You must meet the following requirements in order to effectively follow along with this article:

Creating our landing page in ButterCMS

To make use of ButterCMS, a user account on the platform is required. If you do not already have one, navigate in your browser to the ButterCMS login page and create a new user account.

Upon signing into your account, you will be redirected to a dashboard similar to the image below: 

Welcome page in ButterCMS

Creating a hero section

For the landing page, we will be using the Pages content type. You can find the Pages option on the left sidebar. Here, click on the New Page button, and select create a new page from the dropdown menu. This will open up the content structure configuration page:

Page type configuration page

The first item we will add here is a Component Picker. With this, we will select the Hero component provided by ButterCMS.

Select the component picker

In addition to the fields provided by the Hero component, we will add two additional fields: a media field called “Logo” for the site logo and a repeater field for the site navigation items. We will add these fields to the hero component we added with the component picker.

The repeater will contain a short text for each navigation item:

Hero section configuration

Click on the Save button to finalize the changes made. 

Creating a services section

For the Service section, we will add an additional component named "Services Section" to our page. This component will contain the following fields: a repeater called "Service" which will contain a media field, a shorttext field, and a longtext field called “item”, “item name”, and “item description”, respectively. The fields will contain the name of items, their images, and descriptions of the services offered by the company.

Services section configuration

Creating a products section

Here, create another component called "Product Section". This component will have a repeater called “product card” that contains a media field “product”, a title short text called “product title”, a  long text field called “product description”, and a short text field called “cta button” for a call-to-action button.

Products section configuration

Creating a testimonials section

In this section, we will create another component called the "Testimonial Section". It will contain a repeater field called “Customer feedback” for the products. We will have a media field called “customer image” for the customer image, a short text field called “customer name” for the name, a long text field called “customer response” for the description, and a number field called “customer rating” for the customer rating.

testimonials section configuration

With all the sections added, click on the Create Page Type button to save the created page. For the Page Type name, we will use “ButterCMS Landing Page”.

Adding content to our ButterCMS landing page

To add items to the newly created page type, select the plus icon next to the created page on the left sidebar:

Select our new page type from the side menu

Before we can fill in the site sections, we are prompted to input a Page Title. For this tutorial, we will use “Happy feet” as the title. Fill in the different sections with your desired content. In the end you should have a fully filled page similar to the GIF below:

Add content to our content fields

Click on the Publish button to save your entries when you’re done filling up the fields.

Setting up our frontend

For this tutorial, we will use Next.js and Tailwind CSS to build our application. To install this on your local machine, open a directory of your choice and enter the following command in the CLI:

//create a new next app
npx create-next-app happyfeet

// install the TailwindCSS dependency
npm install -D tailwindcss postcss autoprefixer axios
npx tailwindcss init -p

Once the installation is completed, open up the project directory in your code editor and make the following change to tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

In globals.css, add the following Tailwind style directives to enable the usage of Tailwind utilities in your application:

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

For each section of our site, we will have a separate component. In the project directory, create a folder called components and create the following files in it: Landing.jsx, Services.jsx, Product.jsx, and Testimonial.jsx.  To connect our application to ButterCMS, we will need a read token. This can be found in the Settings section of the left sidebar menu in your ButterCMS account. 

In the pages folder, add the following code to index.js:

import Landing from "../components/Landing";
import Products from "../components/Products";
import Services from "../components/Services";
import Testimonial from "../components/Testimonial";
import { React, useEffect, useState } from "react";
import axios from "axios";

export default function Home() {
  const readtoken = "your read token here";
  const [page, setPage] = useState([]);
  useEffect(() => {
    const getPageData = async () => {
      await axios
        .get(
          `https://api.buttercms.com/v2/pages/buttercms_landing_page/happy-feets/?auth_token=${readtoken}`
        )
        .then((res) => {
          setPage(res.data.data.fields);
        })
        .catch((err) => {
          console.log(err);
        });
    };
    getPageData();
  }, []);
  return (
    <div>
      <Landing content={page.landing_section}/>
      <Services content={page.services_section}/>
      <Products content={page.product_section}/>
      <Testimonial content={page.testimonial_section}/>
    </div>
  );
}

Here, we made a fetch request using Axios to the ButterCMS page content we created. Then, we passed the response as props to our components, each with the appropriate data. 

Building the landing section (i.e., hero section)

To create the landing section, add the following code to Landing.jsx:

import { React } from "react";
const Landing = ({ content }) => {
  
  return (
    <div>
      {/* Navigation Menu */}
      <div>
        <nav className=" shadow-lg fixed w-full z-10 backdrop-blur-md">
          <span className="w-full">
            <div className="flex items-center h-20 w-full">
              <div className="flex items-center items mx-20 justify-between w-full">
                <span className="flex items-center justify-center gap-4 ">
                  {/* site Logo */}
                  <img
                    src={`${content ? content[0].fields.logo : ""}`}
                    height={70}
                    width={70}
                  />
                  {/* company name */}
                  <h1 className=" font-bold cursor-pointer text-xl">
                    Happy<span className=" text-[#ffed02]">Feet</span>
                  </h1>
                </span>
                <span className="hidden md:block">
                  <div className=" ml-10 flex items-baseline space-x-4">
                    {/* navigation list items */}
                    {content
                      ? content[0].fields.navigation.map((item) => {
                          return (
                            <a
                              key={item.nav_item}
                              className="cursor-pointer hover:bg-[#ffed02] text-black hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                            >
                              {item.nav_item}
                            </a>
                          );
                        })
                      : ""}
                  </div>
                </span>
              </div>
            </div>
          </span>
        </nav>
      </div>
      {/* landing section */}
      <div className=" h-screen">
        <div className=" relative" id="Home">
          <div className=" relative w-full h-full top-36 flex justify-center flex-col sm:flex-row">
            <div className=" pl-10 md:w-3/6 sm:w-screen">
              <h2 className=" text-4xl font-semibold mt-24 mb-10 ">
                {/* welcome text */}
                Welcome to <span className=" text-[#a3a1fd]">HappyFeet</span>
              </h2>
              <h4 className=" text-2xl">
                {/* Headline Text */}
                {`"${content[0]?.fields.headline}"`}
              </h4>
              {/* Descriptive text */}
              <h4 className=" pt-2 pl-3 " >{content[0]?.fields.subheadline}</h4>
              <button className=" text-white rounded-md px-12 py-4 mt-10 font-semibold border-2 border-[#a3a1fd] bg-[#a3a1fd] hover:bg-white hover:text-[#a3a1fd] ">
              {/* cta button */}
              {content[0]?.fields.button_label}
              </button>
            </div>
            <span className="h-full w-3/6 relative flex justify-center items-center sm:w-full effect">
                {/* landing hero image */}
              <img
                src={`${content ? content[0].fields.image : ""}`}
                height={950}
                width={950}
              />
            </span>
          </div>
        </div>
      </div>
    </div>
  );
};
export default Landing;

If we run our code with the npm run dev command in the CLI, we can preview our landing section:

Rendered hero section

Adding the services section

For our services page, we will have a grid of three cards containing information on the services rendered. To do this, add the following code to Services.jsx:

import React from "react";
const Services = (content) => {
 
  return (
    <div className="w-full h-[80vh] flex items-center flex-col overflow-hidden">
      <h1 className=" font-mono font-semibold text-3xl mt-24 mb-20 ">
        "A Comfortable, Sleek Sneaker Brand"
      </h1>
      {/* services cards */}
      <div className=" flex gap-12 " >
        {content.content
          ? content.content.service.map((item, index) => {
              return (
                <div className=" w-[500px] flex justify-center items-center flex-col py-5 px-4 shadow-md ">
                  <img src={`${item.item}`} height={200} width={200} />
                  <p className="font-medium text-2xl" >{item.item_name}</p>
                  <p className=" text-xl " >{item.item_description}</p>
                </div>
              );
            })
          : null}
      </div>
    </div>
  );
};
export default Services;

When we run our code, we get the following result:

Rendered services section

See how Butter's simple content api works with your next.js app

Building the products section

To create the products section of the site, add the following code to Product.jsx:

import React from "react";
const Products = (content) => {

  return (
    <div className=" w-screen min-h-screen flex items-center flex-col overflow-hidden">
      <h1 className=" font-mono font-semibold text-3xl mt-24 mb-20 ">
        "A Comfortable, Sleek Sneaker Brand"
      </h1>
      {/* product cards */}
      {content.content
        ? content.content.product_card.map((item, index) => {
            return (
              <div key={index} className=" flex flex-col items-center">
                <div
                  className={` w-max-content overflow-hidden flex gap-8 mb-10 ${
                    index % 2 === 0 ? "flex-row-reverse pl-24 " : "flex-row"
                  }  `}
                >
                  <span className=" w-[700px] flex justify-center items-center h-80 bg-[#a3a1fd] ">
                    {/* product image */}
                    <img src={`${item.product}`} height={350} width={350} />
                  </span>
                  <span className=" bg-white w-[700px] ">
                    <h3 className=" font-medium text-2xl mb-4 ">
                      {/* product title */}
                      {item.product_title}
                    </h3>
                    <h3 className=" max-w-md text-xl ">
                      {/* product description */}
                      {item.product_description}
                    </h3>
                    <button className=" text-white rounded-md px-8 py-4 mt-3 font-semibold border-2 border-[#a3a1fd] bg-[#a3a1fd] hover:bg-white hover:text-[#a3a1fd] ">
                      {/* cta button */}
                      {item.cta_button}
                    </button>
                  </span>
                </div>
              </div>
            );
          })
        : null}
    </div>
  );
};
export default Products;

With this, we get the product image when we run our application:

Rendered product section

Building the testimonials section

We will create the testimonials section in the Testimonial component. To do this, add the following code to Testimonial.jsx:

import React from "react";
const Testimonial = (content) => {
  console.log(content);
  return (
    <div className="w-full h-[80vh] flex items-center flex-col overflow-hidden">
      <h1 className=" font-mono font-semibold text-3xl mt-24 mb-20 ">
        "Testimonies from our Customers"
      </h1>
      {/* testimonial cards */}
      <div className=" flex gap-14 ">
        {content.content
          ? content.content.customer_feedback.map((item, index) => {
              return (
                <div className=" w-[500px] flex justify-center items-center flex-col py-8 px-4 shadow-md ">
                  <img src={`${item.customer_image}`} height={200} width={200} />
                  <p className="font-medium text-2xl my-4 ">{item.customer_name}</p>
                  <p className=" text-xl ">{item.customer_response}</p>
                </div>
              );
            })
          : null}
      </div>
    </div>
  );
};
export default Testimonial;

The resulting application

Congratulations on making it this far! Hurray! You have successfully created a landing page using ButterCMS and Next.js. Running your application will produce the following results:

Rendered application

Closing thoughts

Congratulations on completing this tutorial! You should now have your very own Next.js e-commerce landing page. This article has taught us the foundations of creating an effective landing page that might potentially turn visitors into paying customers. We have demonstrated how to create a landing page by utilizing the cutting-edge tools of Next.js, Tailwind CSS, and ButterCMS, a headless CMS which facilitates the creation of our landing page. For further reading, you could as well go through these articles:

Make sure you receive the freshest Next.js tutorials and Butter product updates.
Marvel Ken

Marvel is a front-end developer and a huge fan of new technologies. He enjoys trying new things out and understanding them so he can teach and share them with others.

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!