Raddy Website Design & Development Tutorials

Create Responsive Side Navigation using TailwindCSS & AlpineJs

By Raddy in CSS / HTML5 / JavaScript ·

In this tutorial, we are going to create a simple, accessible and responsive navigation menu bar and side menu using TailwindCSS v3.0 and Alpine.js. For those of you who would prefer a Video Tutorial you can watch it here:

Before we get started let’s get familiar with the “ingredients” that will help us cook our Navigation bar and Hamburger Menu.

AlpineJs is a rugged, minimal tool for composing behaviour directly in your markup. Think of it like jQuery for the modern web. It’s super easy to get started and build web interactions that normally require a little bit more effort.

TailwindCSS is a utility-first CSS framework packed with ready to cook classes such as flex, pt-4, text-center and rotate that can be composed to build any design, directly in your markup.

What makes both AlpineJs and TaiwindCSS is that they can be used without ever leaving your HTML.

What you will learn:

  • HTML5
  • How to use TailwindCSS from a CDN
  • Basic AlpineJs
  • How to use ARIA Labels
  • Basic Responsive Web Design Princibles

1) Project Setup

In this tutorial, we are only going to have one ‘index.html‘ file and we will link AlpineJs and TaiwindCSS via CDN. I suggest that you use the TailwindCSS CDN only for development purposes. The file is fairly large and it’s not the best choice for production. If you would like to use TailwindCSS for production you can use the Tailwind CLI, PostCSS or any of the Framework Guides that they have.

For those who are not familiar with TailwindCSS, I do have a super-quick free crash course that uses the Tailwind CLI.

The last thing that you need to have in mind is that we are going to develop the menu starting from small screens and working our way up.

Creating a basic HTML5 Project

Let’s start by creating a very basic HTML5 file and we can call our file ‘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">
  <title>Document</title>
</head>
<body>
  
</body>
</html>

Inside our ‘<head>’ element is where we can add the links to the TailwindCSS and AlpineJs CDN.

<script src="https://cdn.tailwindcss.com"></script>
<script src="//unpkg.com/alpinejs" defer></script>

Let’s add both scripts into the HTML head element. I will add some dummy h1 heading element with ‘Hello World’ inside it and a few TailwindCSS class names ‘text-3xl font-bold underline’ to test the styles.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  <h1 class="text-3xl font-bold underline">Hello world!</h1>
</body>
</html>

Testing the website

Open your website in the browser to see if everything is looking good. I usually use Visual Studio Code with the Live Server Plugin installed. It saves me time not having to refresh the browser manually every time I make a change.

So here is the result!

TailwindCSS
Hello World Example

2) Creating Main Header

Let’s start building the Main Header of our website which essentially contains our Main Navigation bar. This Navigation Bar will consist of 3 main elements. The Website Logo, Menu and the Hamburger Menu Button.

As you can see I’ve kept the styling to a minimum. You can always enhance your navigation bar by putting your own logo, colours and fonts.

Menu Parts

Let’s create our HTML5 Header element inside the ‘body’ tag of our page.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  
  <!-- Add This START -->
  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">
    <!-- Logo Goes Here -->
    <!-- Hamburger Menu Button Goes Here -->
    <!-- Main Menu Goes Here -->
  </header>
  <!-- Add This END -->
  
</body>
</html>

As you can see I’ve added a few class names on our HTML5 header element. The most important classes here for me are the ‘flex’ and ‘justify-between’. The colours are important, but I will leave that up to you. In this situation, we are using CSS flexbox to justify our elements and push them like in the photo below.

Mobile menu example
flex container

We don’t have the element created just yet, but we will do that next.

The logo is going to be visible on any screen size. I also want the logo to be vertically centre-aligned and I want it to function as a back button.

To create the logo we can simply use a link and inside that link, we can have our text, image or SVG. To do this add the following code inside the header element.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  
  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">
    
    <!-- Add This START -->
    <a href="/" class="text-lg font-bold">Logo</a>
    <!-- Add This END -->
    
    <!-- Hamburger Menu Button Goes Here -->
    <!-- Main Menu Goes Here -->
  </header>
  
</body>
</html>

Hamburger Menu

Since we are working with smaller screens first, let’s add the Hamburger Menu Button.

The Hamburger Menu Button is going to be a button element with an SVG icon to make it look like a Hamburger Menu. The icon I used is from HeroIcons.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  
  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">
    
    <a href="/" class="text-lg font-bold">Logo</a> <!-- Add This -->
    
    <!-- Add This START -->
    <button class="flex md:hidden flex-col items-center align-middle">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>
    <!-- Add This END -->
    
    <!-- Main Menu Goes Here -->
    
  </header>
  
</body>
</html>

There are a few important things that you need to notice. We are again using Flexbox to align everything inside the button and also we have this ‘md:hidden’ class name. The ‘md:hidden’ class hides our Hamburger Button when the screen’s width is above 768px. That is how we use breakpoints in TailwindCSS.

Mobile menu example

Navigation Bar

For the navigation bar, we can use the HTML5 nav element. Inside the nav element, we can structure everything into an unordered list using ‘ul’ and ‘li’. Each link will be wrapped into an ‘a’ element. Add the highlighted code below:

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  
  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">
    
    <a href="/" class="text-lg font-bold">Logo</a> <!-- Add This -->
    
    
    <button class="flex md:hidden flex-col items-center align-middle">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>
    
    <!-- Add This START -->
    <nav class="hidden md:flex">

      <ul class="flex flex-row gap-2">
        <li>
          <a href="#" class="inline-flex py-2 px-3 bg-slate-200 rounded" aria-current="true">Home</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">About</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Articles</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Contact</a>
        </li>
      </ul>

    </nav>
    <!-- Add This END -->
    
  </header>
  
</body>
</html>

The important bit here is to notice that we have a ‘hidden md:flex’ on the nav element. This hides the navigation on smaller screens and it appears above 768px (md screen). It’s kind of the opposite of what we added on the hamburger menu button.

flex container

Responsive Test

Save your project and try it out on different screen sizes. You can simply resize your browser to see how everything behaves.

Hopefully, on mobile you should see something like this:

Tailwind Navigation Hamburger Menu
Below 768px (md)

And on larger screens:

Tailwind Navigation
Above 768px (md)

Mobile Pop-Out Menu

Next, we need to create and style our Mobile Menu. This menu will be triggered once the Hamburger Menu has been pressed. I am going to keep the styling very basic.

We need:

  • Close Button
  • List with links
Mobile Menu Fly-out

Creating the Pop out Navigtion

Let’s wrap this navigation into a ‘nav’ HTML5 element. Inside it, we will have our close button and an unordered list.

Note that this needs to be added outside the main header element as we need to be able to position it on top of every other element of the page. This will also allow us to make it full with and full height when activated.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
  
  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">
    
    <a href="/" class="text-lg font-bold">Logo</a> <!-- Add This -->
    
    
    <button class="flex md:hidden flex-col items-center align-middle">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>
    
    <nav class="hidden md:flex">

      <ul class="flex flex-row gap-2">
        <li>
          <a href="#" class="inline-flex py-2 px-3 bg-slate-200 rounded" aria-current="true">Home</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">About</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Articles</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Contact</a>
        </li>
      </ul>

    </nav>
    
  </header>
  
  <!-- Add This START -->
  <nav id="mobile-navigation" class="fixed top-0 right-0 bottom-0 left-0 backdrop-blur-sm z-10">

    <!-- UL Links -->
    <ul class="absolute top-0 right-0 bottom-0 w-10/12 py-4 bg-white drop-shadow-2xl z-10 transition-all">

      <li class="border-b border-inherit">
        <a href="#" class="block p-4" aria-current="true">Home</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">About</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Articles</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Contact</a>
      </li>

    </ul>

    <!-- Close Button -->
    <button class="absolute top-0 right-0 bottom-0 left-0">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 absolute top-2 left-2" fill="none" viewBox="0 0 24 24"
        stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>

  </nav>
  <!-- Add This END -->
  
</body>
</html>

Note that:

  • The navigation is fixed and it starts from top, right, bottom and left set to 0.
  • The close button is absolute to the fixed navigation element and it starts from top, right, bottom and left set to 0.
  • The Unordered List (UL) is also absolute to the fixed navigation but it is not full with. Instead it takes roughtly 80% (w-10/12) of the available space.

3) Interaction Using AlpineJs

It’s time to make our mobile navigation work using AlpineJs.

The idea is that when we press on the Hamburger Menu Button the “Pop-Out” menu animates out. Note that some animations are not great for accessibility. We will work on this later on in this tutorial under the Accessibility section.

The two states to make this work. Let’s call them “Default State” and “Active State“.

default state
Default State
opened state
Active State

With AlpineJs we can use ‘x-data’ to declare an object of data that Alpine will track. To make this simple let’s call our data ‘openMenu’ and set it to ‘false’ as the default state. Essentially we want to have an event listener toggle the ‘openMenu’ between ‘true’ or ‘false’.

Let’s do this line by line as it might be easier.

Line 13 (Body Element):

  • Declare data openMenu set to false ‘x-data=”{ openMenu : false }”‘
  • Toggle the ‘overflow-hidden’ : ‘overflow-visible’ class names if ‘openMenu is true or false :class=”openMenu ? ‘overflow-hidden’ : ‘overflow-visible’

Line 27 (Hamburger Button):

  • Add an event listener to toggle openMenu between true or false ‘@click=”openMenu = !openMenu”‘

Line 80 (Close Button):

  • Add an event listener to toggle openMenu between true or false ‘@click=”openMenu = !openMenu”‘

Line 16 + 58 (Hide Pop Out navigation):

  • On line 16 copy the ‘x-cloak’ css styles and on line 58 add a class name of ‘x-cloak’

Sometimes, when you’re using AlpineJS for a part of your template, there is a “blip” where you might see your uninitialized template after the page loads, but before Alpine loads.

x-cloak addresses this scenario by hiding the element it’s attached to until Alpine is fully loaded on the page.

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>

<body x-data="{ openMenu : false }" :class="openMenu ? 'overflow-hidden' : 'overflow-visible' ">

  <style>
    [x-cloak] {
      display: none !important;
    }
  </style>

  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">

    <!-- Logo -->
    <a href="/" class="text-lg font-bold">Logo</a>

    <!-- Mobile Menu Toggle -->
    <button class="flex md:hidden flex-col items-center align-middle" @click="openMenu = !openMenu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>

    <!-- Main Navigations -->
    <nav class="hidden md:flex">

      <ul class="flex flex-row gap-2">
        <li>
          <a href="#" class="inline-flex py-2 px-3 bg-slate-200 rounded" aria-current="true">Home</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">About</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Articles</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Contact</a>
        </li>
      </ul>

    </nav>

  </header>


  <!-- Pop Out Navigation -->
  <nav class="fixed top-0 right-0 bottom-0 left-0 backdrop-blur-sm z-10" :class="openMenu ? 'visible' : 'invisible' " x-cloak>

    <!-- UL Links -->
    <ul class="absolute top-0 right-0 bottom-0 w-10/12 py-4 bg-white drop-shadow-2xl z-10 transition-all"
      :class="openMenu ? 'translate-x-0' : 'translate-x-full'">

      <li class="border-b border-inherit">
        <a href="#" class="block p-4" aria-current="true">Home</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">About</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Articles</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Contact</a>
      </li>

    </ul>

    <!-- Close Button -->
    <button class="absolute top-0 right-0 bottom-0 left-0" @click="openMenu = !openMenu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 absolute top-2 left-2" fill="none" viewBox="0 0 24 24"
        stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>

  </nav>

</body>
</html>

That’s it! Your menu should be working at this point.

Making It Accessible

Let’s make our menu as accessible as possible. To do this we are mainly going to focus on adding ARIA labels, but I also have a full list below on things that you should strongly consider.

ARIA provides several mechanisms for adding labels and descriptions to elements. In fact, ARIA is the only way to add accessible help or description text. Let’s look at the properties ARIA uses to create accessible labels.

https://developers.google.com/web/fundamentals/accessibility/semantics-aria/aria-labels-and-relationships

Things to consider when designing accessible elements:

Links source: https://www.w3.org/WAI/tips/designing/

ARIA Labels

Let’s get familiar with the labels we need. Most of them are self-explanatory:

  • aria-expanded=”set to true or false”
  • aria-controls=”The ID of the element controlled. Example: mobile-navigation”
  • aria-label=”Example labe: Navigation Menu”
  • aria-current=”If current page set to ‘true'”

aria-expanded

The aria-expanded attribute is set on an element to indicate if a control is expanded or collapsed, and whether or not its child elements are displayed or hidden. (Source Developer.Mozilla.Org)

aria-controls

The global aria-controls property identifies the element (or elements) whose contents or presence are controlled by the element on which this attribute is set. (Source Developer.Mozilla.Org)

aria-label

The aria-label attribute defines a string value that labels an interactive element. (Source Developer.Mozilla.Org)

aria-current

A non-null aria-current state on an element indicates that this element represents the current item within a container or set of related elements. (Source Developer.Mozilla.Org)

Let’s do this line by line as it might be easier.

Line 28 (Hamburger Button):

  • We need to add the following: ‘:aria-expanded=”openMenu” aria-controls=”mobile-navigation” aria-label=”Navigation Menu”

Line 41 (Current Link):

  • Add: ‘aria-current=”true”

Line 60 (Navigation ID):

  • Add: “id=”mobile-navigation”

Line 83 (Close Button):

  • Add: :aria-expanded=”openMenu” aria-controls=”mobile-navigation” aria-label=”Close Navigation Menu”.
<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>

<body class="bg-[url('unsplash.jpg')] bg-cover" x-data="{ openMenu : false }"
  :class="openMenu ? 'overflow-hidden' : 'overflow-visible' ">

  <style>
    [x-cloak] {
      display: none !important;
    }
  </style>

  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">

    <!-- Logo -->
    <a href="/" class="text-lg font-bold">Logo</a>

    <!-- Mobile Menu Toggle -->
    <button class="flex md:hidden flex-col items-center align-middle" @click="openMenu = !openMenu"
      :aria-expanded="openMenu" aria-controls="mobile-navigation" aria-label="Navigation Menu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>

    <!-- Main Navigations -->
    <nav class="hidden md:flex">

      <ul class="flex flex-row gap-2">
        <li>
          <a href="#" class="inline-flex py-2 px-3 bg-slate-200 rounded" aria-current="true">Home</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">About</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Articles</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Contact</a>
        </li>
      </ul>

    </nav>

  </header>


  <!-- Pop Out Navigation -->
  <nav id="mobile-navigation" class="fixed top-0 right-0 bottom-0 left-0 backdrop-blur-sm z-10"
    :class="openMenu ? 'visible' : 'invisible' " x-cloak>

    <!-- UL Links -->
    <ul class="absolute top-0 right-0 bottom-0 w-10/12 py-4 bg-white drop-shadow-2xl z-10 transition-all"
      :class="openMenu ? 'translate-x-0' : 'translate-x-full'">

      <li class="border-b border-inherit">
        <a href="#" class="block p-4" aria-current="true">Home</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">About</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Articles</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Contact</a>
      </li>

    </ul>

    <!-- Close Button -->
    <button class="absolute top-0 right-0 bottom-0 left-0" @click="openMenu = !openMenu" :aria-expanded="openMenu"
      aria-controls="mobile-navigation" aria-label="Close Navigation Menu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 absolute top-2 left-2" fill="none" viewBox="0 0 24 24"
        stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>

  </nav>

</body>
</html>

Reduce Motion – Animations

Earlier in this tutorial, I mentioned that sometimes animations might not be great for accessibility. For situations where the user has specified that they prefer reduced motion, you can conditionally apply animations and transitions using the motion-safe and motion-reduce variants:

<button type="button" class="bg-indigo-600 ..." disabled>
  <svg class="motion-safe:animate-spin h-5 w-5 mr-3 ..." viewBox="0 0 24 24">
    <!-- ... -->
  </svg>
  Processing
</button>

Final Code

<!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">
  <title>Document</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="//unpkg.com/alpinejs" defer></script>
</head>

<body class="bg-[url('unsplash.jpg')] bg-cover" x-data="{ openMenu : false }"
  :class="openMenu ? 'overflow-hidden' : 'overflow-visible' ">

  <style>
    [x-cloak] {
      display: none !important;
    }
  </style>

  <header class="flex justify-between items-center bg-white drop-shadow-sm py-4 px-8">

    <!-- Logo -->
    <a href="/" class="text-lg font-bold">Logo</a>

    <!-- Mobile Menu Toggle -->
    <button class="flex md:hidden flex-col items-center align-middle" @click="openMenu = !openMenu"
      :aria-expanded="openMenu" aria-controls="mobile-navigation" aria-label="Navigation Menu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
      </svg>
      <span class="text-xs">Menu</span>
    </button>

    <!-- Main Navigations -->
    <nav class="hidden md:flex">

      <ul class="flex flex-row gap-2">
        <li>
          <a href="#" class="inline-flex py-2 px-3 bg-slate-200 rounded" aria-current="true">Home</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">About</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Articles</a>
        </li>
        <li>
          <a href="#" class="inline-flex py-2 px-3 hover:bg-slate-200 rounded">Contact</a>
        </li>
      </ul>

    </nav>

  </header>

  <!-- Pop Out Navigation -->
  <nav id="mobile-navigation" class="fixed top-0 right-0 bottom-0 left-0 backdrop-blur-sm z-10"
    :class="openMenu ? 'visible' : 'invisible' " x-cloak>

    <!-- UL Links -->
    <ul class="absolute top-0 right-0 bottom-0 w-10/12 py-4 bg-white drop-shadow-2xl z-10 transition-all"
      :class="openMenu ? 'translate-x-0' : 'translate-x-full'">

      <li class="border-b border-inherit">
        <a href="#" class="block p-4" aria-current="true">Home</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">About</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Articles</a>
      </li>
      <li class="border-b border-inherit">
        <a href="#" class="block p-4">Contact</a>
      </li>

    </ul>

    <!-- Close Button -->
    <button class="absolute top-0 right-0 bottom-0 left-0" @click="openMenu = !openMenu" :aria-expanded="openMenu"
      aria-controls="mobile-navigation" aria-label="Close Navigation Menu">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 absolute top-2 left-2" fill="none" viewBox="0 0 24 24"
        stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>

  </nav>

</body>
</html>

That’s all!

I hope that the tutorial was clear and informative. It’s fairly difficult to nail it on the first go, but I will try to add and improve on it with time. Saying this, if you have ANY suggestions on how to make the tutorial a little bit easier to understand please do let me know. Nevertheless, If you found this tutorial useful let me know in the comments below. This way I will know if I should be making more.

Thank you for reading this tutorial.

More Resources:

Thank you for reading this article. Please consider subscribing to my YouTube Channel. It’s FREE!

  1. Erdem says:

    Thank you so much for this example code.

    1. Raddy says:

      Glad to heat that you found it useful

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.