Emmanuel Akhigbe Full-stack web developer and designer. I love learning and writing code to solve problems. Twitter:

Building an ecommerce storefront with Storefront UI and Tailwind CSS

8 min read 2348

Building an ecommerce storefront with Storefront UI and Tailwind CSS

In this article, we’ll build a storefront with Storefront UI and Tailwind CSS.

What is Storefront UI?

Storefront UI is a Vue component library — currently, a stable beta — that offers a well thought out design system of ecommerce components. It follows atomic design principles, which is great for building scalable and maintainable frontend applications. It is also compatible with the Google UX Playbook for retail.

Why Storefront UI?

  • Great customization options: You can customize Storefront UI components (atoms, molecules, and organisms) easily through props, slots, and CSS variables. You can also customize the way your components look with Tailwind CSS, as we’ll do here
  • Mobile-first: Rest assured your components are responsive
  • Performance: You don’t need to import components you don’t need. Storefront UI ships the raw source, which means you can benefit from build-time optimizations like tree shaking or grouping common chunks. It only bundles what you import
  • Accessibility: It is dedicated to ecommerce and has all the elements/components necessary for building a modern online store. These components are also accessible and are based on the Google UX Playbook

What is Tailwind CSS?

Tailwind CSS is an awesome utility-first CSS framework that makes styling components simple and fast. You can add classes like flex, pt-4, and text-center in the class attribute of your markup for styling.

Why Tailwind CSS?

  • Makes styling faster: No need to manually write CSS, SCSS, or Less styles
  • Makes styling easy: You don’t need to leave your markup file while styling
  • Intuitive class names: Class names couldn’t be simpler. For example, mb-0 means margin-bottom set to 0 and pt-0 means padding-top set to 0. It’s also easy to stay consistent with color choices, spacing, typography, shadows, and everything else that makes up a well-engineered design system. You define classes only once, and these classes are used throughout the application

Building a storefront

To better understand Storefront UI, we’ll use it to build a storefront.

finished ui for storefront ui project

Installation and file setup

Create a Vue application with the following command:

vue create <app-name>

If you don’t have Vue installed on your machine, you can check Vue’s installation guide on how to install it.

Now, install Storefront UI:

npm install --save @storefront-ui/vue

Import Storefront UI global styles — these will be added to the main.js file in the root directory of your project:

import "@storefront-ui/vue/styles.scss";

Install Tailwind CSS:

We made a custom demo for .
No really. Click here to check it out.

install -D [email protected]:@tailwindcss/postcss7-compat

@tailwindcss/postcss7-compat [email protected]^7 [email protected]^9

Generate your tailwind.config.js and postcss.config.js files:

npx tailwindcss init -p

Create the ./src/index.css file and paste in the following code to import Tailwind’s base, components, and utilities styles:

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

Import the index.css file to your root main.js file:

import './index.css'

Check that your installation works by starting up the Vue project and importing a Storefront UI link atom into your App.vue file:

// App.vue file
<template>
  <div>
        <SfLink link="/">Home</SfLink>
  </div>
</template>
 <script>
  import { SfLink} from "@storefront-ui/vue";
  export default {
    components: {
    SfLink,
    },
  };
</script>
<style></style>

If all is well, you should see a nice link.

You can adjust the font size of the link: Tailwind provides a class for adjusting font sizes. Add a class attribute to the SfLink component, and give it a value of text-lg. If you save the file and check your browser, you should see that the font size has changed.

You can also access and use Storefront UI CSS variables with Tailwind. If you want access to the CSS variables, here’s what your tailwind.config.js file will look like:

module.exports = {
  purge: [],
  important: true,
  theme: {
    extend: {
      fontSize: {
        "sf-xs": "var(--font-size--xs)", //12px
        "sf-sm": "var(--font-size--sm)", //14px
        "sf-base": "var(--font-size--base)", //16px
        "sf-lg": "var(--font-size--lg)", //18px
    },
      fontWeight: {
        "sf-light": "var(--font-weight--light)", //300
        "sf-normal": "var(--font-weight--normal)", //400
        "sf-medium": "var(--font-weight--medium)", //500
        "sf-semibold": "var(--font-weight--semibold)", //600
        "sf-bold": "var(--font-weight--bold)", //700
    },
    colors: {
        "sf-c-black": "var(--c-black)", // #1d1f22
        "sf-c-black-base": "var(--c-black-base)", // #1d1f22
       "sf-c-black-lighten": "var(--c-black-lighten)", // #292c30
        "sf-c-black-darken": "var( --c-black-darken)", // #111214
        "sf-c-white": "var(--c-white)", // #ffffff
        "sf-c-body": "var(--c-body)", // #ffffff
        "sf-c-text": "var(--c-text)", // #1d1f22
        "sf-c-text-muted": "var(--c-text-muted)", // #72757E
        "sf-c-text-disabled": "var(--c-text-disabled)", // #e0e0e1
        "sf-c-link": "var(--c-link)", // #43464E
        "sf-c-link-hover": "var(--c-link-hover)", // // #1d1f22
        "sf-c-primary": "var(--c-primary)", // #5ece7b
        "sf-c-primary-base": "var(--c-primary-base)", // #5ece7b
        "sf-c-primary-lighten": "var(--c-primary-lighten)", // #72d48b
        "sf-c-primary-darken": "var(--c-primary-darken)", // #4ac86b
        "sf-c-primary-variant": "var(--c-primary-variant)", // #9ee2b0
        "sf-c-on-primary": "var(--c-on-primary)", // #ffffff
        "sf-c-secondary": "var( --c-secondary)", // #1d1f22
        "sf-c-secondary-base": "var(--c-secondary-base)", // #1d1f22
        "sf-c-secondary-lighten": "var(--c-secondary-lighten)", // #292c30
        "sf-c-secondary-darken": "var(--c-secondary-darken)", // #111214
        "sf-c-secondary-variant": "var(--c-secondary-variant)", // #43464E
        "sf-c-on-secondary": "var(--c-on-secondary)", //  #ffffff
        "sf-c-light": "var(--c-light)", // #f1f2f3
        "sf-c-light-base": "var(--c-light-base)", // #f1f2f3
        "sf-c-light-lighten": "var(--c-light-lighten)", // #ffffff
        "sf-c-light-darken": "var(--c-light-darken)", // #e3e5e7
        "sf-c-light-variant": "var(--c-light-variant)", //  #ffffff
        "sf-c-on-light": "var(--c-on-light)", // #1d1f22
        "sf-c-gray": "var(--c-gray)", // #72757E
        "sf-c-gray-base": "var(--c-gray-base)", // #72757E
        "sf-c-gray-lighten": "var(--c-gray-lighten)", // #7f828b
        "sf-c-gray-darken": "var(--c-gray-darken)", // #666971
        "sf-c-gray-variant": "var(--c-gray-variant)", // #8D8F9A
        "sf-c-on-gray": "var(--c-on-gray)", // #1d1f22
        "sf-c-dark": "var(--c-dark)", // #1d1f22
        "sf-c-dark-base": "var(--c-dark-base)", // #1d1f22
        "sf-c-dark-lighten": "var(--c-dark-lighten)", // #292c30
        "sf-c-dark-darken": "var(--c-dark-darken)", // #111214
        "sf-c-dark-variant": "var(--c-dark-variant)", // #43464E
        "sf-c-on-dark": "var(--c-on-dark)", //  #ffffff
        "sf-c-info": "var(--c-info)", //  #0468DB
        "sf-c-info-base": "var(--c-info-base)", //  #0468DB
        "sf-c-info-lighten": "var(--c-info-lighten)", // #0474f4
        "sf-c-info-darken": "var(--c-info-darken)", // #045cc2
        "sf-c-info-variant": "var(--c-info-variant)", // #e1f4fe
        "sf-c-on-info": "var(--c-on-info)", //  #ffffff
        "sf-c-success": "var(--c-success)", // #5ece7b
        "sf-c-success-base": "var(--c-success-base)", // #5ece7b
        "sf-c-success-lighten": "var(--c-success-lighten)", // #72d48b
        "sf-c-success-darken": "var(--c-success-darken)", // #4ac86b
        "sf-c-success-variant": "var(--c-success-variant)", // #9ee2b0
        "sf-c-on-success": "var(--c-on-success)", //  #ffffff
        "sf-c-warning": "var(--c-warning)", // #ecc713
        "sf-c-warning-base": "var(--c-warning-base)", // #ecc713
        "sf-c-warning-lighten": "var(--c-warning-lighten)", //  #eecd2b
        "sf-c-warning-darken": "var(--c-warning-darken)", // #d4b311
        "sf-c-warning-variant": "var(--c-warning-variant)", // #f6e389
        "sf-c-on-warning": "var(--c-on-warning)", //  #ffffff
        "sf-c-danger": "var(--c-danger)", //  #d12727
        "sf-c-danger-base": "var(--c-danger-base)", //  #d12727
        "sf-c-danger-lighten": "var(--c-danger-lighten)", // #da3838
        "sf-c-danger-darken": "var(--c-danger-darken)", //  #bc2323
        "sf-c-danger-variant": "var(--c-danger-variant)", // #fcede8
        "sf-c-on-danger": "var(--c-on-danger)", // #ffffff
    },
      spacing: {
        "sf-2xs": "var(--spacer-2xs)", // 4px
        "sf-xs": "var( --spacer-xs)", // 8px
        "sf-sm": "var(--spacer-sm)", // 16px
        "sf-base": "var(--spacer-base)", // 24px
        "sf-lg": "var(--spacer-lg)", // 32px
        "sf-xl": "var(--spacer-xl)", // 40px
        "sf-2xl": "var(--spacer-2xl)", // 80px
        "sf-3xl": "var(--spacer-3xl)", // 160px
    },
      fontFamily: {
        "sf-primary": "var(--font-family--primary)", // "Roboto", serif
        "sf-secondary": `var(--font-family--secondary)`, // "Raleway", sans-serif
    },
    },
  },
  variants: {},
  plugins: [],
};

Paste this code above into your tailwind.config.js file and save. Go back to your App.vue file and change the class value in the SfInput component to text-sf-lg. Voilà! You’re now using Storefront UI’s CSS variables through Tailwind to style components.

Building the navbar

To build the navbar of the storefront, create a header file in the components directory and paste the following code in the file:

//VittyHeader.vue
<template>
  <div>
    <SfHeader
      logo="https://www.svgrepo.com/show/9395/ribbon-banner-silhouette.svg"
      title="Storefront UI"
      cartIcon="empty_cart"
      wishlistIcon="heart"
      accountIcon="profile"
      searchPlaceholder="Search for items"
      searchValue=""
      wishlistItemsQty="0"
      cartItemsQty="0"
    >
      <template v-slot:navigation>
        <navigation-links />
      </template>
    </SfHeader>
  </div>
</template>
 
<script>
  import { SfHeader } from "@storefront-ui/vue";
  import NavigationLinks from "./NavigationLinks.vue";
  export default {
    components: {
      SfHeader,
      NavigationLinks,
    },
  };
</script>
<style></style>

Here, we import the SfHeader organism. This component makes use of named slots, one of which is navigation. We’ll use this slot to add navigation links to the SfHeader component.

//NavigationLinks.vue
<template>
  <ul class="flex gap-x-5">
    <li><SfLink class="text-sf-lg" link="/">Home</SfLink></li>
    <li><SfLink class="text-sf-lg" link="/about">About</SfLink></li>
    <li><SfLink class="text-sf-lg" link="/contact">Contact</SfLink></li>
  </ul>
</template>
<script>
  import { SfLink } from "@storefront-ui/vue";
  export default {
    components: {
      SfLink,
    },
  };
</script>
<style></style>

Remember to clear out your App.vue file and import your header component to see how it looks in the browser.

Building the carousel molecule

Storefront UI uses Glide.js for its carousels. Here we can see options for customizing the carousel, like the perView property, which is used to control the number of slides visible at once. We will be using the SfHero to create sliders in the storefront. If you need to use the options provided by Glide.js, you can use the carousel component:

// VittyHero.vue
<template>
  <SfHero>
    <SfHeroItem
      title="Colorful summer dresses are already in store"
      subtitle="Summer Collection 2019"
      buttonText="Learn more"
      background="#ECEFF1"
      image="https://images.unsplash.com/photo-1483985988355-763728e1935b?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1950&q=80"
    />
    <SfHeroItem
      buttonText="Learn more"
      background="#ECEFF1"
      image="https://images.unsplash.com/photo-1596149615678-8488f200b301?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1189&q=80"
    >
      <template v-slot:subtitle>
        <h1 class="sf-hero-item__subtitle text-white">Summer Collection 2019</h1>
      </template>
      <template v-slot:title>
        <h1 class="sf-hero-item__title text-white">Colorful summer dresses are already in store</h1>
      </template>
    </SfHeroItem>
  </SfHero>
</template>
<script>
  import { SfHero } from "@storefront-ui/vue";
  export default {
    data: () => ({}),
    components: {
      SfHero,
    },
  };
</script>
<style></style>

The SfHeroItem component is auto-imported as a child component of the SfHero. In the code snippet above, we utilize the subtitle and title named slots to change the default color of the text so that it is more visible on the hero image.

Building the home products molecule

To build the home product section, we’ll use the SfSection component to create a section in the storefront, the SfCarousel component, which will accept a settings property for carousel customization. We will also use the SfProductCard component to render product information.

The titleHeading property in the SfSection component is used to set the section header text, and the levelHeading property determines the size of this text heading:

<template>
  <div>
    <SfSection :titleHeading="title" :levelHeading="2">
      <SfCarousel :settings="settings">
        <SfCarouselItem v-for="(n, index) in new Array(6)" :key="index">
          <SfProductCard
            image="https://img.rawpixel.com/s3fs-private/rawpixel_images/website_content/363-mj-3796-ae-a-l.jpg?w=800&dpr=1&fit=default&crop=default&q=65&vib=3&con=3&usm=15&bg=F4F4F3&ixlib=js-2.2.1&s=67561fcc6e2a6442637577f7abb7ad68"
            :imageWidth="216"
            :imageHeight="326"
            title="Cotton Sweater"
            :scoreRating="4"
            :reviewsCount="7"
            :maxRating="5"
            wishlistIcon="heart"
            isOnWishlistIcon="heart_fill"
            showAddToCartButton
          />
        </SfCarouselItem>
      </SfCarousel>
    </SfSection>
  </div>
</template>
 
<script>
  import { SfProductCard, SfCarousel, SfSection } from "@storefront-ui/vue";
  export default {
    data: () => ({
      settings: { perView: 3 },
    }),
    components: {
      SfProductCard,
      SfCarousel,
      SfSection,
    },
    props: {
      title: {
        type: String,
        required: true,
    },
    },
  };
</script>
<style></style>

Building the banner section

To build the banner section, we’ll use Storefront UI’s SfBanner which has a slot named call-to-action where we can use the SfButton component:

<template>
  <div class="container w-full mx-auto" style="max-width:1100px">
    <SfBanner
      title="Eco Sandals"
      subtitle="Summer shoes"
      description="The collection features formal and casual comfort shoes with a Danish design focus. Made from premium leathers and comfort."
      image="https://images.unsplash.com/photo-1572206443494-b07cc12d6921?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=633&q=80"
    >
      <template v-slot:call-to-action>
        <SfButton>
          Shop Now
        </SfButton>
      </template>
    </SfBanner>
  </div>
</template>
<script>
  import { SfBanner, SfButton } from "@storefront-ui/vue";
  export default {
    components: {
      SfBanner,
      SfButton,
    },
  };
</script>
<style></style>

Building the showcase section

To build this section, we’ll use the SfSection component and the SfImage component. The SfImage component can cast a dark overlay on an image and display some text that was passed as a child. This can be seen in the first three images:

<template>
  <SfSection titleHeading="Be In Tune" subtitleHeading="#OppOpgOpk" :levelHeading="2">
    <div class="px-14 grid w-full">
      <div class="a p-2">
        <SfImage          src="https://images.unsplash.com/photo-1556905055-8f358a7a47b2?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80"
          :srcsets="[]"
          alt="Vila stripe maxi shirt dress"
          width=""
          height=""
        >
          A
        </SfImage>
      </div>
      <div class="b p-2">
        <SfImage
          class="object-cover"         src="https://images.unsplash.com/photo-1562157873-818bc0726f68?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=564&q=80"
         :srcsets="[]"
          alt="Vila stripe maxi shirt dress"
          width=""
          height="100%"
        >
          B
        </SfImage>
      </div>
      <div class="c p-2">
        <SfImage
          class="object-cover"        src="https://images.unsplash.com/photo-1562157873-818bc0726f68?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=564&q=80"
          :srcsets="[]"
          alt="Vila stripe maxi shirt dress"
          width=""
          height="100%"
        >
          C
        </SfImage>
      </div>
      <div class="d p-2">
        <SfImage       src="https://images.unsplash.com/photo-1556905055-8f358a7a47b2?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1050&q=80"
          :srcsets="[]"
          alt="Vila stripe maxi shirt dress"
          width=""
          height=""
        />
      </div>
    </div>
  </SfSection>
</template>
<script>
  import { SfSection, SfImage } from "@storefront-ui/vue";
  export default {
    components: {
      SfSection,
      SfImage,
    },
  };
</script>
<style>
  .a {
    grid-column: 1;
    grid-row: 1;
  }
  .b {
    grid-column: 1;
    grid-row: 2 / span 2;
  }
  .c {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
  .d {
    grid-column: 2;
    grid-row: 3;
  }
</style>

Conclusion

Well done! You have come this far. In this article, we have looked at what Storefront UI is, how to set it up, and how to use Tailwind for CSS customization. We have also learned about how to use some components by building a nice storefront. Feel free to get the code from my GitHub repo here.

LogRocket: See the technical and UX reasons for why users don’t complete a step in your ecommerce flow.

LogRocket is like a DVR for web apps and websites, recording literally everything that happens on your ecommerce app. Instead of guessing why users don’t convert, LogRocket proactively surfaces the root cause of issues that are preventing conversion in your funnel, such as JavaScript errors or dead clicks. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.

Start proactively monitoring your ecommerce apps — .

Emmanuel Akhigbe Full-stack web developer and designer. I love learning and writing code to solve problems. Twitter:

Leave a Reply