Home » BLOG » Web development » Building Landing Page with Tailwind CSS – Final

Building Landing Page with Tailwind CSS – Final

category:  Web development

A few days ago, I wrote Building Landing Page with Tailwind CSS – Part1. Today it is the final part. We will build the simple landing page with Tailwind CSS.

Landing Page

Below is the landing page we will build today. We have both desktop and mobile version. We also build for the tablet version as well which will look the same as mobile version.

Landing page - desktop
Landing page on desktop
Landing page - mobile
Landing page on mobile

The mobile menu will be a simple dropdown menu which is controlled by JavaScript. It looks like the screen below.

tailwind-lp-dropdown-menu
dropdown menu on tablet and mobile

Style guide

Color

We will use blue color as the main color of our landing page. We also have black, dark gray, light gray and gray color as well. We will add these color via config file.

tailwind-lp-blue-shade
Surf Blue Color

Fonts

We will use self-hosting fonts and web font in our landing page. So you will learn how to add the custom fonts from both sources.

For self-hosting fonts, we will use Antic and Bebas fonts which you can download from github. You will add these fonts into fonts folder.

For web font, we will use Roboto which we will add the CDN link into our index.html which is the main file for our project. We will add the CDN link later.

We will add these fonts via config file.

We will use logo font which is Antic.

Images (assets)

You can download the images for this tutorial from github. All images will be stored in “img” folder.

Dist folder

In our tutorial, everything in “dist” folder will be used for production.

Index.html

Okay, now fonts and images are set. Next, we will start by adding the HTML markup in index.html. From Part 1, index.html is in the root. But in Part 2, I design to move index.html into “dist” folder. So your file structure will look like this.

|- tailwind-lp (root folder)
|– dist/index.html (our main file)
|– src/tailwind.css (Tailwind stylesheet)
|– dist/style.css (generate by Tailwind CLI later)

Now, adding the code below into your index.html.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:[email protected];400;500;700&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <title>Tailwind CSS - Simple Landing Page</title>
</head>

<body>

    <!-- header STARTs -->    
    <header class="mx-auto px-8 bg-cover bg-no-repeat" style="background-image: url('img/hero-image.jpg');">

        <!-- Nav bar -->
        <nav class="flex justify-between py-5 text-white lg:px-16 ">

            <!-- logo -->
            <div class="py-4 logo uppercase text-white text-2xl filter drop-shadow-md">
                SURF BROS</div>

            <!-- menus bar -->
            <div class="py-4 text-right">
                <!-- menu button -->
                <button id="btn-menu" class="relative top-2 lg:hidden">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                        <path fill-rule="evenodd"
                            d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
                            clip-rule="evenodd" />
                    </svg>
                </button>

                <!-- menus list -->
                <ul id="menus" class="hidden mt-4 lg:mt-0 lg:flex lg:gap-2">
                    <li><a href="#" class="menu-link">home</a></li>
                    <li><a href="#" class="menu-link">about</a></li>
                    <li><a href="#" class="menu-link">testimonial</a></li>
                    <li><a href="#" class="menu-link">contact us</a></li>
                    <li class="mt-2 lg:mt-0">
                        <span class="btn"><a href="#" class="menu-link">reservation</a></span>
                    </li>
                </ul>

            </div>
        </nav>


        <!-- Hero section -->
        <section
            class="flex flex-col items-center sm:py-14 lg:px-5 lg:py-10 xl:px-16 xl:py-32 lg:flex-row lg:flex-wrap lg:justify-evenly">
            <!-- text -->
            <h1
                class="text-white text-8xl py-2 sm:text-9xl md:mt-10 lg:mt-0 lg:py-0 lg:text-7xl xl:text-9xl 2xl:text-10xl opacity-75 filter drop-shadow">
                explore<br>your
                nature
            </h1>
            <!-- image -->
            <img src="img/woman-surfing.png" alt="woman-surfing"
                class="py-12 sm:w-11/12 md:p-12 md:mb-10 lg:w-2/4 lg:mb-0 lg:p-0 xl:w-6/12">
        </section>

    </header>
    <!-- header ENDs -->


    <!-- section STARTS -->
    <main class="py-20 px-8 flex flex-col-reverse gap-20 lg:flex-row lg:py-20 lg:px-20 xl:px-10 2xl:py-32">

        <!-- image -->
        <div class="flex-1 w-full self-center md:py-20 lg:pr-10 lg:py-10 xl:pr-0">
            <img src="img/founder-surf-bros.png" alt="Surf Bros Founder" class="w-max lg:w-full">
        </div>

        <!-- text -->
        <div class="flex-1 self-center xl:pr-20 xl:pl-0">
            <h1
                class="pb-10 text-7xl gradient-header-title sm:text-8xl md:text-8xl md:py-10 lg:text-6xl xl:text-7xl 2xl:text-9xl 2xl:pt-0">
                explore phuket beach today!
            </h1>

            <h4 class="pb-10 text-4xl sm:text-4xl md:pb-5 lg:text-2xl xl:text-4xl 2xl:text-6xl">Lorem ipsum dolor, sit
                amet
                consectetur
                adipisicing elit.
            </h4>

            <p class="text-lg">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eos quas atque, maiores
                voluptatibus sequi
                autem, aspernatur nam quos ipsam soluta debitis sit assumenda pariatur magnam? Repudiandae illo debitis
                doloremque itaque. Lorem ipsum, dolor sit amet consectetur adipisicing elit. </p>

            <!-- button -->
            <div>
                <a href="#"
                    class="btn btn-surf mt-10 p-3 capitalize text-xl inline-block sm:text-3xl 2xl:mb-10 2xl:text-4xl">explore
                    more
                    exciting</a>
            </div>

        </div>
    </main>
    <!-- section ENDS -->



    <!-- section STARTS -->
    <section class="py-20 px-8 bg-surf-light-gray sm:py-36 xl:pt-32 xl:pb-0">

        <!-- title -->
        <h2 class="pb-24 text-center text-7xl sm:text-8xl lg:text-8xl">how awesome <br
                class="hidden md:block lg:block">we are
        </h2>

        <!-- features list -->
        <ul class="feature-list">
            <li class="feature-item">

                <!-- image -->
                <div style="background-image: url('img/tall-tress.jpg')"
                    class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
                    <img src="img/tall-tress.jpg" alt="tall trees" class="w-full object-cover opacity-0">
                </div>

                <!-- text -->
                <div class="bg-white flex-1 2xl:flex-size-2">
                    <span
                        class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">01.</span>
                    <p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
                        dolorum.
                        Adipisci incidunt
                        unde
                        voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
                        vel
                        non in.
                        Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
                        adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
                        blanditiis provident fugit fuga.
                    </p>
                    <a href="#"
                        class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
                        more</a>
                </div>
            </li>
            <li class="feature-item">

                <!-- image -->
                <div style="background-image: url('img/man-sitdown.jpg')"
                    class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
                    <img src="img/man-sitdown.jpg" alt="" class="w-full object-cover opacity-0">
                </div>

                <!-- text -->
                <div class="bg-white flex-1 2xl:flex-size-2">
                    <span
                        class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">02.</span>
                    <p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
                        dolorum.
                        Adipisci incidunt
                        unde
                        voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
                        vel
                        non in.
                        Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
                        adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
                        blanditiis provident fugit fuga.
                    </p>
                    <a href="#"
                        class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
                        more</a>
                </div>
            </li>
            <li class="feature-item">

                <!-- image -->
                <div style="background-image: url('img/man-with-surf.jpg')"
                    class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
                    <img src="img/man-with-surf.jpg" alt="" class="w-full object-cover opacity-0">
                </div>

                <!-- text -->
                <div class="bg-white flex-1 2xl:flex-size-2">
                    <span
                        class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">03.</span>
                    <p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
                        dolorum.
                        Adipisci incidunt
                        unde
                        voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
                        vel
                        non in.
                        Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
                        adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
                        blanditiis provident fugit fuga.
                    </p>
                    <a href="#"
                        class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
                        more</a>
                </div>
            </li>
            <li class="feature-item">

                <!-- image -->
                <div style="background-image: url('img/surfing.jpg')"
                    class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
                    <img src="img/surfing.jpg" alt="" class="w-full object-cover opacity-0">
                </div>

                <!-- text -->
                <div class="bg-white flex-1 2xl:flex-size-2">
                    <span
                        class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">04.</span>
                    <p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
                        dolorum.
                        Adipisci incidunt
                        unde
                        voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
                        vel
                        non in.
                        Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
                        adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
                        blanditiis provident fugit fuga.
                    </p>
                    <a href="#"
                        class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
                        more</a>
                </div>
            </li>
        </ul>
    </section>
    <!-- section ENDS -->


    <!-- section STARTS -->
    <section class="py-20 px-8 flex flex-col sm:flex-row sm:items-end">
        <div class="flex-1 md:flex-size-1 lg:flex-1 xl:pl-28 2xl:flex-size-1">
            <h3 class="text-surf-dark-gray text-4xl lg:text-6xl">subscribe</h3>
            <div class="text-surf-blue font-Bebas text-3xl relative inset-x-3 -inset-y-2 lg:text-6xl">get our latest
                news</div>
        </div>

        <div class="flex-1 md:flex-size-2 lg:flex-1 2xl:flex-size-2">
            <form action="#" class="py-2 flex gap-1 md:justify-center lg:justify-start lg:pb-4">
                <input type="email" placeholder="Your Email"
                    class="ring-1 ring-surf-gray bg-surf-light-gray px-2 py-1 rounded outline-none lg:w-4/6 xl:w-4/6 2xl:w-3/6">
                <button
                    class="bg-surf-blue text-white font-Bebas px-5 py-1 rounded hover:bg-surf-dark-gray outline-none lg:text-2xl xl:text-3xl 2xl:text-5xl">go!</button>
            </form>
        </div>
    </section>
    <!-- section ENDS -->


    <hr class="border border-gray-300 border-opacity-30">


    <!-- footer STARTS-->
    <footer class="px-8 pt-5 pb-10 flex flex-col text-center sm:flex-row sm:justify-between">
        <div class="text-surf-gray">[email protected] <span class="uppercase">surf bros</span></div>
        <div class="text-surf-gray">powered by <a href="https://applerinquest.com" title="WordPress developer"
                class="text-surf-blue capitalize">apple rinquest</a>
        </div>
    </footer>
    <!-- footer ENDS -->

</body>


<!-- Javascript STARTS -->
<script>

    // # menu button
    document.getElementById("btn-menu").addEventListener("click", openDropDownMenu);

    // # show dropdown menu
    function openDropDownMenu() {
        const menus = document.getElementById("menus");

        if (menus.style.display === "none" || menus.style.display.length === 0) {
            menus.style.display = "block";
        } else {
            menus.style.display = "none";
        }
    }

</script>
<!-- Javascript ENDS -->

</html>

HTML5 doctype

You should use HTML5 doctype for Tailwind. With HTML5, we will be sure that Tailwind’s style will work as expected.

If you view the index.html using Live Server extension in VS code, the result will look like this.

tailwind-lp-screen-nostyle-1
Landing page without style

Header section

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- add Google web font -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:[email protected];400;500;700&display=swap" rel="stylesheet">

    <link rel="stylesheet" href="style.css">

    <title>Tailwind CSS - Simple Landing Page</title>
</head>

In header section, we add the Google web font which is Roboto. We also add style.css which is generated by Tailwind Cli from Part 1. Moreover, we use HTML5 doctype and responsive view port meta tag.

Tailwind.css, tailwind.config.js, style.css

Tailwind.css

Default Tailwind Style, Components and Utilities

Tailwind.css contains @tailwind directive and our custom style. From Part 1, we only add three tailwind’s directives as shown below.

/* https://tailwindcss.com/docs/functions-and-directives */
/* ./src/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Base style is a global styles at the beginning of stylesheet. It is built on top of modern-normalize. Tailwind automatically injects the style by using ‘@tailwind base’ in your CSS. When you want to add your own style, you will apply the style by using ‘@layer base‘.

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

@layer base {
  h1 {
    @apply text-2xl;
  }
  h2 {
    @apply text-xl;
  }
}

Components, it is basically dealing with duplication style that apply to the common elements such as button, images, form and so on. Components are really useful when your project is getting bigger and more complex. With components, you can maintain the duplicated style in one place. Tailwind automatically injects your custom components by using ‘@layer components‘ in your CSS.

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

@layer components {
  .btn-blue {
    @apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
  }
}

Utilities, Tailwind provides a ton of utility classes for you. But in some situation, you may need your own. Tailwind allows you to extend the utilities by using ‘@layer utilities‘ in your CSS.

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

@layer utilities {
  .scroll-snap-none {
    scroll-snap-type: none;
  }
  .scroll-snap-x {
    scroll-snap-type: x;
  }
  .scroll-snap-y {
    scroll-snap-type: y;
  }
}

Add our custom style in Tailwind.css

Next, we will add our own style for our landing page in Tailwind.css.

/* https://tailwindcss.com/docs/functions-and-directives */
/* ./src/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;


/* https://tailwindcss.com/docs/functions-and-directives#layer */
@layer base {
    /* # add custom font by self-hosting */
    /* https://tailwindcss.com/docs/adding-base-styles#font-face-rules */
    @font-face {
        font-family: "Antic";
        font-weight: regular;
        src: url('./fonts/ANTICFONT.woff') format('woff');
    }
    @font-face {
        font-family: "Bebas";
        font-weight: regular;
        src: url('./fonts/Bebas-Regular.woff') format('woff');
    }

    body, nav {
        @apply font-Roboto text-base;
    }

    p {
        @apply text-surf-dark-gray;
    }

    h1, h2, h3, h4, h5, h6 {
        @apply font-Bebas text-surf-dark-gray;
    }

    .logo {
        @apply font-Antic;
    }

    /* menu link */
    ul#menus li {
        @apply py-1;
    }
    ul#menus li a.menu-link {
        @apply mt-1 p-2 text-white text-center uppercase hover:text-surf-black transition duration-500;
    }

    .gradient-header-title {
        @apply text-transparent bg-clip-text from-surf-blue-100 to-surf-blue-900 bg-gradient-to-r;
    }
}

/* we add the repeat style for each HTML element in components */
@layer components {
    /* button */
    .btn {
        @apply text-white rounded-lg ring-white ring-2 p-2 transition duration-500 hover:ring-surf-black;
    }
    .btn-surf {
        @apply text-surf-blue rounded-xl ring-surf-blue text-4xl hover:ring-surf-dark-gray hover:text-surf-dark-gray;
    }    
    button {
        @apply transition duration-500;
    }

    /* feature list */
    .feature-list {
        @apply flex flex-col text-center flex-wrap lg:flex-row xl:text-left xl:pt-20;
    }
    .feature-item {
        @apply lg:w-2/4 xl:flex xl:flex-row xl:mb-28;
    }    
    .feature-item:nth-child(odd) {
        @apply xl:pr-10;
    }
}

For the code above, we apply our own base style and components using @layer directive. Layer directive will tell Tailwind where our custom style will be injected.

We also use @apply directive for applying any existing utility classes into our custom CSS.

How to apply the utility classes in HTML or Tailwind CSS

To learn how to use utility classes, visit Tailwind doc and review the existing utilities from there.

Add utility classes in HTML mark up

For example, you want to add padding as 0 to an image element in HTML markup. The utility class you will use, is p-0. What you have to do, just apply p-0 via class attribute of the image element.

<!-- apply padding:0 using Tailwind utility class -->
<img src=".." alt=".." class="p-0">

<!-- normal CSS without Tailwind utility class used -->
<img src=".." alt=".." style="padding:0;">

Add utility classes in Tailwind CSS

Also, you can add the padding to the image element via Tailwind CSS.

@layer base {
   img {
     @apply p-0;
   }
}

tailwind.config.js

As I mention at the Style guide section, we will add our own color and fonts for our landing page. To do that, we will add color and fonts in tailwind.config.js which we already generated from Part 1.

generating config file

If you don’t have the config file yet, you can generate one by using this command in terminal.

npx tailwindcss init

Here is the minimal config file that is generated by init command.

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

Now, you will replace the config file with this code.

module.exports = {
  purge: ['./dist/**/*.html'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {
      // # add new background image
      // https://tailwindcss.com/docs/background-image#background-images
      // backgroundImage: theme => ({
      //   'hero-image': "url('./img/hero-image.jpg')",
      // }),
      // # add new custom colors
      // https://tailwindcss.com/docs/customizing-colors#extending-the-defaults
      colors: {
        'surf-blue': {
          100: "#84D8EB",
          200: "#73D3E8",
          300: "#61CDE5",
          400: "#50C8E2",
          DEFAULT: "#38C1DF",
          500: "#2CBCDD",
          600: "#22B2D3",
          700: "#1FA3C1",
          800: "#1D95AF",
          900: "#1A869E",
        },
        'surf-black': { DEFAULT: "#17272b" },
        'surf-dark-gray': { DEFAULT: "#7a7a7a" },
        'surf-light-gray': { DEFAULT: "#eeeeee" },
        'surf-gray': { DEFAULT: "#dddddd" },
      },
      // # add new custom fonts (can use Google font or self-hosting)
      // https://tailwindcss.com/docs/font-family#customizing
      fontFamily: {
        'Roboto': "'Roboto', sans-serif",
        'Antic': "'Antic', san-serif",
        'Bebas': "'Bebas', san-serif",
      },
      // # add new custom font size 
      // https://tailwindcss.com/docs/font-size#font-sizes
      fontSize: {
        '10xl': '10rem'
      },
      // # add new custom flex
      flex: {
        'size-1': '1',
        'size-2': '2'
      },
    },
  },
  variants: {
    extend: {
      // # generate hover and active variants for ringColor
      // https://tailwindcss.com/docs/ring-color#variants
      ringColor: ['hover', 'active'],
    },

  },
  plugins: [

  ],
}

Purge option

Purge option, this option is integrated with PurgeCSS by Tailwind. PurgeCSS will remove the unused CSS from the templates.

In our config file, we specific the templates( ‘./dist/**/*.html’ ) we want Purge to scan and remove unused CSS from style.css. Purge option is an array. You can add more templates and pattern you want.

Dark mode option

DarkMode option, in this tutorial, we don’t use dark mode. But you can read more about dark mode and try by yourself.

Theme option

Theme option, this option allows you to define your own color palette, fonts, border, breakpoints and more.

In our config file, we add new color palette, fonts, font size and flex attribute in extend option. We add the new custom as extend option because we don’t want to override the default theme. But if you want to override the default theme, you can add your override directly under theme option.

// tailwind.config.js
module.exports = {
  theme: {
    // Replaces all of the default `opacity` values
    opacity: {
      '0': '0',
      '20': '0.2',
      '40': '0.4',
      '60': '0.6',
      '80': '0.8',
      '100': '1',
    }
  }
}

Variants option

Variants option, this option allows you to generate utility variants you want for each core plugin.

In our config file, we want to generate hover and active variants for ringColor class. The ring color will set the color for box-shadow property. By default, Tailwind doesn’t provide these variants but we will use them for our landing page. So we will generate those utilities for ring-color class.

For Tailwind, if you need more utility variants for core plugin which are not generated by default, you can simple add them in config file at variants option. For overriding, you can add them directly in variants option. For extending, you can add them in extend option under variants option.

Plugins option

Plugins option, currently Tailwind provides four official plugins to use. Those are Typography, Forms, Aspect Ratio and Line Clamp. In our tutorial, we don’t use any of them.

For adding plugins, you can simply install the plugins then add them into the config file. After that, you will build the stylesheet using Tailwind Cli.

Form plugin

For example, you want to use the Form plugin for basic resetting the form styles. This way, you can use the Tailwind utilities without any cross browser compatibility issues. The form plugin is useful for styling checkbox, select box, dropdown and more. BTW, Form plugin is designed for Tailwind CSS v2.0.

In order to use form plugin, you need to install the plugin using npm in terminal.

npm install @tailwindcss/forms

Then add the plugin into the config file as below.

// tailwind.config.js
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require('@tailwindcss/forms'),
    // ...
  ],
}

Finally, building the CSS file using Tailwind cli. That’s it. You can style your form using Tailwind utility classes.

Build Style.css from Tailwind.css

Once we add the custom style in tailwind.css, we need to build the stylesheet for production using Tailwind cli.

npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css

By running the build command, tailwind will look at the config file (tailwind.config.js) first then look at tailwind.css and lastly tailwind will generate the style.css for production.

After the style.css is built, you should see the final result for our landing page as below.

Building Landing Page Tutorial
Tailwind Landing page for desktop
Building Landing Page Tutorial

Tailwind Landing page for mobile

tailwind-lp-dropdown-menu
Dropdown menu for tablet and mobile

Miscellaneous

Tailwind CSS IntelliSense extension

In VS code, you can install and enable Tailwind CSS IntelliSense extension. This extension will show the Tailwind utility classes while you are working on the templates (HTML, JSX and so on). In order to activate this extension, you need to install tailwindcss and have a tailwind config file names tailwind.config.js in your workspace.

PostCSS Language Support extension

In VS code, if you see some warning below, you will need PostCSS extension for it.

need postcss

Responsive Design

Similar to other CSS frameworks, Tailwind provides five breakpoints by default.

Breakpoint prefixMinimum widthCSS
sm640px@media (min-width: 640px) { … }
md768px@media (min-width: 768px) { … }
lg1024px@media (min-width: 1024px) { … }
xl1280px@media (min-width: 1280px) { … }
2xl1536px@media (min-width: 1536px) { … }
5 breakpoint by common device resolutions

With Tailwind, all you need to do is prefix the utility with breakpoint name (sm, md, lg, xl, 2xl). You can add the utility classes without leaving HTML. It is really cool. You can use the breakpoint name by adding the breakpoint name following to comma and then add the utility class.

For example, our landing page, we want to show the hamburger menu when the screen size is less than 1024px. Here is the code.

<!-- menu button -->
<button id="btn-menu" class="relative top-2 lg:hidden">
    <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
        <path fill-rule="evenodd"
            d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
            clip-rule="evenodd" />
    </svg>
</button>

From the code, we add the hidden class to hide the dropdown menu when the screen size is bigger than 1024px. In the code, we simply add “lg:hidden” class at the button element. That’s it. It is very easy to use.

Another example, let’s say you want to add the different padding value for each breakpoint, you can do as shown below.

<button id="btn-menu" class="relative top-2 lg:hidden p-1 sm:p-2 md:p-3 lg:p-4 xl:p-5 2xl:p-6">

</button>

Tailwind doesn’t use the breakpoints to target the devices. All breakpoints, they are just the breakpoint. Meaning, the sm breakpoint is not for the mobile device. Since Tailwind uses mobile first breakpoint system so any utility classes without breakpoint prefix will take effect for all screen sizes. So the p-1 class will take effect for all screen sizes until the screen size hits 640px (sm), the p-2 class will then take effect for 640px breakpoint and wider screen. Once the screen size hits 768px (md), the p-3 class will then take effect and so on. You get this.

The breakpoint name works for every utility class in the framework

Since you can use breakpoint name for every utility class in the framework, you can change anything at the given breakpoint. This is really cool.

Mobile First

By default, Tailwind uses a mobile first breakpoint system. Any utility classes without breakpoint prefix will take effect for all screen sizes.

In Tailwind, the sm prefix doesn’t mean to target the mobile device. Instead, it targets the small breakpoint. Tailwind uses unprefixed utilities to target mobile and override them at larger breakpoints. Below is an example.

<!-- This will center text on mobile, and left align it on screens 640px and wider -->
<div class="text-center sm:text-left"></div>

Hover, Focus, Other States

In our landing page, we use hover state for the button. Similar to breakpoint prefix, Tailwind use the states following comma and then the utility class. See the example below.

<button class="bg-surf-blue text-white font-Bebas px-5 py-1 rounded hover:bg-surf-dark-gray outline-none lg:text-2xl xl:text-3xl 2xl:text-5xl">go!</button>

For the code above, we add the hover state and change the background color to dark gray. All we need to do, we just add ” hover:bg-surf-dark-gray” class at the button element.

Note that, not all state variants are enabled by default. If you want to generate some for your project, you can add them to the tailwind config file as shown below. Then run the build command at the terminal.

  variants: {
    extend: {
      // # generate hover and active variants for ringColor
      // https://tailwindcss.com/docs/ring-color#variants
      ringColor: ['hover', 'active'],
    },

  },

How do you know you need to generate new state for the core plugin, the easy way is, you just build the style without Purge config in the tailwind config file. Then you check the state with utility classes you want in the built CSS file. If you don’t find any state with utility classes you want then you will add those states into the config file and run the build command for generating them.

Container

Unlike containers in other frameworks, Tailwind’s container doesn’t center itself automatically. Also it doesn’t have any built-in horizontal padding. Because Tailwind wants to totally reset the style and let you add your style you want from start.

To center a container, just use ‘mx-auto‘ utility. It will add margin-left and margin-right as auto.

To add horizontal padding, use ‘px-{size}‘ utility. For example, adding px-4, it will add padding-left and padding-right as 1 rem.

If you like to center by default, you can add the config in the config file.

Flexbox and Grid

Tailwind provides you with Flexbox and Grid utilities which are easy to use. If you need more Flexbox and Grid properties, you just simply add the new properties into the config file.

Remove unused CSS

In our landing page, we can remove the unused CSS from style.css. This way, our style.css will be smaller size.

To do that, we add the templates we want Purge to scan in the config file. In our case, it is the index.html. But I like to add the pattern instead of specific file name. Below is the example.

module.exports = {
  purge: ['./dist/**/*.html'],
...

Next, we will run the build command by adding the NODE_ENV with production as shown below.

NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css

NODE_ENV with production will tell Tailwind cli to use PurgeCSS.

With this command, it will look for the config file first and then read the purge option. In this case, it finds ‘ ./dist/**/*.html ‘ at purge option. So Purge will scan all html files under “dist” folder to find the used Tailwind CSS and then Purge will remove the unused Tailwind CSS from style.css. The result is, style.css is smaller size.

Minify CSS file

Just like other CSS preprocessors (Sass or Less), Tailwind can do minify CSS. Tailwind uses cssnano for this. Simply add –minify at the build command as shown below.

NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css --minify

The result is, all comments, space and new line are removed from style.css.

Watch mode

When we develop the project and we need to run the build command manually every time the code changes, it is not fun and it consumes time. Just like other CSS preprocessors, we can add watch mode at the build command like so.

NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css --watch

To kill watch mode, you just hit Ctrl+c in the terminal.

Source code

You can download the source code from github.

Explore more

You should explore Tailwind more at Tailwind’s doc and Tailwind lab YouTube channel.

Wrap up

Tailwind focuses on building complex components from the set of utilities. With the utilities workflow, you can control any pieces of your work and design almost everything. Furthermore, Tailwind doc is well-documented in my opinion.

For the fast development, Tailwind offers the paid UI components that are built with Tailwind CSS as well.

In this tutorial, it explains how to setup Tailwind CSS for your project. It tells you where to add the customization. It also tells you how to use the utility classes in HTML markup and Tailwind CSS. The idea behind the tutorial is, you see the big picture of Tailwind. You get the idea how Tailwind works and how to use Tailwind. Moreover, it tells you what type of projects you should use Tailwind.

That’s it for Tailwind.